最新要闻

广告

手机

iphone11大小尺寸是多少?苹果iPhone11和iPhone13的区别是什么?

iphone11大小尺寸是多少?苹果iPhone11和iPhone13的区别是什么?

警方通报辅警执法直播中被撞飞:犯罪嫌疑人已投案

警方通报辅警执法直播中被撞飞:犯罪嫌疑人已投案

家电

MAUI新生3.5-深入理解XAML:行为Behavior

来源:博客园

通过行为Behavior,可以将功能附加到控件上,而不需要在宿主控件上定义,和扩展方法有异曲同功之妙。在MAUI中实现Behavior,有两种方式:①附加行为;②MAUI内置行为。附加行为,通过附加属性方式实现,可以深入理解行为的内在原理;而MAUI的内置行为,封装了实现细节,使用起来非常简洁。

一、附加行为附加属性可以在非宿主控件类中使用,同时,它也是可绑定属性,可以定义propertyChanged回调函数,在回调函数中可以调用“控件对象、附加属性的新值和旧值”。当控件的附加属性值发生变化时,propertyChanged回调函数执行业务逻辑,从而实现为控件附加功能。这种方式,我们称之为附加行为。


(相关资料图)

1、定义一个行为类(附加属性方式)(在Behaviors文件夹下)

//在Behaviors文件夹下创建立NumberValidateBehavior行为类public class NumberValidateBehavior{    //定义附加属性AttachBehaviorProperty,布尔类型,当值发生改变时propertyChanged,执行OnAttachBehaviorChanged函数    public static readonly BindableProperty AttachBehaviorProperty =        BindableProperty.CreateAttached("AttachBehavior",typeof(bool),typeof(NumberValidateBehavior),false,propertyChanged:OnAttachBehaviorChanged);    public static bool GetAttachBehavior(BindableObject view)    {        return (bool)view.GetValue(AttachBehaviorProperty);    }    public static void SetAttachBehavior(BindableObject view,bool value)    {        view.SetValue(AttachBehaviorProperty, value);    }    //附加属性值发生变化时的回调    //根据附加属性值(true or false),订阅或移除事件TextChanged的处理程序    static void OnAttachBehaviorChanged(BindableObject view,object oldValue,object newValue)    {        //将宿主对象转化为Entry,使用as,要么成功转为Entry,要么返回null。所以,一般行为都只针对特定控件        Entry entry = view as Entry;        if (entry == null)        {            return;        }        //获取附加属性的新值,并根据新值订阅或移除事件处理程序(事件回调)        bool attachBehavior = (bool)newValue;        if (attachBehavior)        {            entry.TextChanged += OnEntryTextChanged;        }        else        {            entry.TextChanged -= OnEntryTextChanged;        }    }    //TextChanged的事件处理程序    //真正给控件附加的功能,如果输入值可以转换为double类型,则字体颜色为黑色,否则为红色    static void OnEntryTextChanged(object sender,TextChangedEventArgs args)    {        double result;        bool isValid = double.TryParse(args.NewTextValue, out result);        ((Entry)sender).TextColor = isValid ? Colors.Black : Colors.Red;    }}

2、使用附加行为

                        

3、删除附加行为

二、内置行为几乎每个MAUI控件,都有一个Behaviors属性,是派生自Behavior类(或Behavior)的对象集合。Behavior类有两个重写方法OnAttachedTo和OnDetachingFrom,可以将附加到控件上的功能写在这两个方法里。当将Behavior对象添加到集合时,执行OnAttachedTo方法,反之将执行OnDetachingFrom。这种方式,我们称之为内置行为。

1、定义一个行为类(派生自Behavior类方式)

//在Behaviors文件夹中创建SimpleNumberValidateBehavior行为类,派生自Behavior,泛型指定为Entry,行为指定应用于Entrypublic class SimpleNumberValidateBehavior: Behavior{    //添加行为时,订阅事件TextChanged的处理程序    protected override void OnAttachedTo(Entry entry)    {        entry.TextChanged += OnEntryTextChanged;        base.OnAttachedTo(entry);    }    //删除行为时,移除事件TextChanged的处理程序    protected override void OnDetachingFrom(Entry entry)    {        entry.TextChanged -= OnEntryTextChanged;        base.OnDetachingFrom(entry);    }    //TextChanged的事件处理程序    //真正给控件附加的功能,如果输入值可以转换为double类型,则字体颜色为黑色,否则为红色    private void OnEntryTextChanged(object sender, TextChangedEventArgs args)    {        double result;        bool isValid = double.TryParse(args.NewTextValue, out result);        ((Entry)sender).TextColor = isValid ? Colors.Black : Colors.Red;    }}

2、使用内置行为

                                                                        

3、删除内置行为:控件的Behaviors属性是一个集合,所以可以在后台代码中移除或清除添加到集合中的行为对象

三、案例:EventToCommandBehavior

1、MVVM开发模式,我们在ViewModel中定义命令,View的控件绑定命令,如【

3、解读EventToCommandBehavior源码

public class EventToCommandBehavior : BaseBehavior{    //=======================================================================================================================================    //定义MethodInfo,方法信息    readonly MethodInfo eventHandlerMethodInfo = typeof(EventToCommandBehavior).GetTypeInfo()?.GetDeclaredMethod(nameof(OnTriggerHandled)) ??                                                  throw new InvalidOperationException($"Cannot find method {nameof(OnTriggerHandled)}");    //定义EventInfo,事件信息    EventInfo? eventInfo;    //定义事件处理委托    Delegate? eventHandler;    //可绑定属性===============================================================================================================================    //可绑定属性EventName-事件    public static readonly BindableProperty EventNameProperty =        BindableProperty.Create(nameof(EventName), typeof(string), typeof(EventToCommandBehavior), propertyChanged: OnEventNamePropertyChanged);    public string? EventName    {        get => (string?)GetValue(EventNameProperty);        set => SetValue(EventNameProperty, value);    }    //可绑定属性Command-命令    public static readonly BindableProperty CommandProperty =        BindableProperty.Create(nameof(Command), typeof(ICommand), typeof(EventToCommandBehavior));    public ICommand? Command    {        get => (ICommand?)GetValue(CommandProperty);        set => SetValue(CommandProperty, value);    }    //可绑定属性CommandParameter-命令参数    public static readonly BindableProperty CommandParameterProperty = ......    //可绑定属性EventArgs-事件参数    public static readonly BindableProperty EventArgsConverterProperty =......        //内置行为的OnAttachedTo和OnDetachingFrom函数===============================================================================================    //添加行为时,执行RegisterEvent函数,注册事件    protected override void OnAttachedTo(VisualElement bindable)    {        base.OnAttachedTo(bindable);        RegisterEvent();    }    //移除行为时,执行UnregisterEvent函数,注销事件    protected override void OnDetachingFrom(VisualElement bindable)    {        UnregisterEvent();        base.OnDetachingFrom(bindable);    }    //可绑定属性EventName的值更改时,执行RegisterEvent函数,注册事件    static void OnEventNamePropertyChanged(BindableObject bindable, object oldValue, object newValue)        => ((EventToCommandBehavior)bindable).RegisterEvent();    //RegisterEvent和UnregisterEven注册和注销事件逻辑,eventHandler在事件和命令之间建立委托=========================================================    void RegisterEvent()    {        UnregisterEvent();        var eventName = EventName;        if (View is null || string.IsNullOrWhiteSpace(eventName))        {            return;        }        //获取eventInfo        eventInfo = View.GetType()?.GetRuntimeEvent(eventName) ??            throw new ArgumentException($"{nameof(EventToCommandBehavior)}: Couldn"t resolve the event.", nameof(EventName));        ArgumentNullException.ThrowIfNull(eventInfo.EventHandlerType);        ArgumentNullException.ThrowIfNull(eventHandlerMethodInfo);        //******添加一个事件处理方法eventHandler,eventHandlerMethodInfo为触发命令的方法******        eventHandler = eventHandlerMethodInfo.CreateDelegate(eventInfo.EventHandlerType, this) ??            throw new ArgumentException($"{nameof(EventToCommandBehavior)}: Couldn"t create event handler.", nameof(EventName));        eventInfo.AddEventHandler(View, eventHandler);    }    void UnregisterEvent()    {        //移处事件处理方法enentHandler,并将eventInfo和eventHandler设置为null        if (eventInfo is not null && eventHandler is not null)        {            eventInfo.RemoveEventHandler(View, eventHandler);        }        eventInfo = null;        eventHandler = null;    }    //定义虚方法OnTriggerHandled,触发命令========================================================================================================    [Microsoft.Maui.Controls.Internals.Preserve(Conditional = true)]    protected virtual void OnTriggerHandled(object? sender = null, object? eventArgs = null)    {        var parameter = CommandParameter            ?? EventArgsConverter?.Convert(eventArgs, typeof(object), null, null);        var command = Command;        if (command?.CanExecute(parameter) ?? false)        {            command.Execute(parameter);        }    }}

关键词: 附加属性 事件处理 回调函数