如何在Xamarin.Forms中实现类似WPF/UWP的Loaded触发命令?
在Xamarin.Forms中实现页面加载时绑定MVVM命令的正确方式
你提到在WPF/UWP里用MVVM Light的EventTriggerBehavior绑定Loaded事件很顺畅,但在Xamarin.Forms里尝试自定义EventToCommandBehavior绑定OnAppearing时遇到了报错。咱们一步步来解决这个问题:
首先明确:Xamarin.Forms里的页面生命周期事件和WPF/UWP不同,而且MVVM Light在Xamarin.Forms中的Behavior实现也有区别,不能直接照搬WPF的写法。
一、先分析你的报错原因
你自定义的EventToCommandBehavior大概率存在实现漏洞,导致反射调用构造函数时出错。另外一个关键错误是:你绑定的OnAppearing是页面代码后台的虚方法,不是Xamarin.Forms的可绑定路由事件,正确的事件名应该是Appearing。
二、正确实现方式(三种可选)
方式1:直接用MVVM Light为Xamarin.Forms适配的Behavior
MVVM Light已经为Xamarin.Forms提供了现成的EventToCommandBehavior,不用自己造轮子:
- 先确认通过NuGet安装了
MvvmLight和MvvmLight.Forms包 - 在XAML中引入命名空间:
xmlns:mvvm="clr-namespace:GalaSoft.MvvmLight.Xamarin.Forms;assembly=GalaSoft.MvvmLight.Forms"
- 绑定
Appearing事件到你的命令:
<ContentPage.Behaviors> <mvvm:EventToCommandBehavior EventName="Appearing" Command="{Binding LoadedCommand}" /> </ContentPage.Behaviors>
方式2:自定义正确的EventToCommandBehavior
如果你坚持自己实现Behavior,下面是一个标准的、避免反射错误的模板:
using System; using System.Reflection; using Xamarin.Forms; namespace XamarinTest.Behaviors { public class EventToCommandBehavior : Behavior<VisualElement> { public static readonly BindableProperty EventNameProperty = BindableProperty.Create(nameof(EventName), typeof(string), typeof(EventToCommandBehavior), null, propertyChanged: OnEventNameChanged); public static readonly BindableProperty CommandProperty = BindableProperty.Create(nameof(Command), typeof(ICommand), typeof(EventToCommandBehavior), null); public string EventName { get => (string)GetValue(EventNameProperty); set => SetValue(EventNameProperty, value); } public ICommand Command { get => (ICommand)GetValue(CommandProperty); set => SetValue(CommandProperty, value); } private EventInfo _targetEvent; protected override void OnAttachedTo(VisualElement bindable) { base.OnAttachedTo(bindable); RegisterEvent(EventName); } protected override void OnDetachingFrom(VisualElement bindable) { DeregisterEvent(EventName); base.OnDetachingFrom(bindable); } private void RegisterEvent(string eventName) { if (string.IsNullOrWhiteSpace(eventName)) return; _targetEvent = AssociatedObject.GetType().GetRuntimeEvent(eventName); if (_targetEvent == null) throw new ArgumentException($"找不到事件 {eventName} 在 {AssociatedObject.GetType().Name} 上"); var handler = _targetEvent.EventHandlerType .GetMethod("Invoke") .CreateDelegate(_targetEvent.EventHandlerType, this, typeof(EventToCommandBehavior).GetMethod("OnEventTriggered")); _targetEvent.AddEventHandler(AssociatedObject, handler); } private void DeregisterEvent(string eventName) { if (_targetEvent == null || string.IsNullOrWhiteSpace(eventName)) return; var handler = _targetEvent.EventHandlerType .GetMethod("Invoke") .CreateDelegate(_targetEvent.EventHandlerType, this, typeof(EventToCommandBehavior).GetMethod("OnEventTriggered")); _targetEvent.RemoveEventHandler(AssociatedObject, handler); _targetEvent = null; } private void OnEventTriggered(object sender, EventArgs e) { if (Command?.CanExecute(e) ?? false) Command.Execute(e); } private static void OnEventNameChanged(BindableObject bindable, object oldValue, object newValue) { var behavior = (EventToCommandBehavior)bindable; if (behavior.AssociatedObject == null) return; behavior.DeregisterEvent((string)oldValue); behavior.RegisterEvent((string)newValue); } } }
然后在XAML中绑定正确的事件名:
<ContentPage.Behaviors> <behaviors:EventToCommandBehavior EventName="Appearing" Command="{Binding LoadedCommand}" /> </ContentPage.Behaviors>
方式3:最简单的替代方案(不用Behavior)
如果不想折腾Behavior,直接在页面代码后台调用ViewModel的命令反而更直观:
public Page1() { InitializeComponent(); BindingContext = App.Locator.UserMainViewModel; } protected override void OnAppearing() { base.OnAppearing(); var viewModel = BindingContext as UserMainViewModel; viewModel?.LoadedCommand.Execute(null); }
三、关键注意事项
- Xamarin.Forms页面的显示触发事件是
Appearing,不是WPF的Loaded,也不要用OnAppearing(这是代码后台的方法名,不是可绑定事件) - 确保你的
RelayCommand是MVVM Light提供的GalaSoft.MvvmLight.Command.RelayCommand,ViewModel的绑定逻辑没有问题(你的绑定代码看起来是对的) - 自定义Behavior时一定要正确处理事件的注册和注销,避免内存泄漏和反射异常
按照上面的方法调整后,你的LoadedCommand应该就能在页面显示时正常触发了。
内容的提问来源于stack exchange,提问作者user7998549
相关产品推荐
相关产品推荐

