MvvmLight MvvmLight主要程序库
ViewModelLocator 在.netFramework环境下nuget安装MvvmLight
会自动安装依赖项MvvmLightLibs
库,如果在.net core环境下需要手动安装MvvmLightLibs
库。
.netFramework环境下安装完成后,在ViewModel目录下具有一个ViewModelLocator
类,该类的作用是提供依赖注入容器和相关属性。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 public class ViewModelLocator { public ViewModelLocator () { ServiceLocator.SetLocatorProvider(() => SimpleIoc.Default); SimpleIoc.Default.Register<MainViewModel>(); SimpleIoc.Default.Register<SubWindowVM>(); } public MainViewModel Main { get { return ServiceLocator.Current.GetInstance<MainViewModel>(); } } public SubWindowVM SubWin { get { return ServiceLocator.Current.GetInstance<SubWindowVM>(); } } public static void Cleanup () {} }
另外,在App.xaml中增加ViewModelLocator
资源
1 2 3 4 5 <Application.Resources > <ResourceDictionary > <vm:ViewModelLocator x:Key ="Locator" /> </ResourceDictionary > </Application.Resources >
这样在MainWindow中就可以这样注册DataContext
1 <Window DataContext ="{Binding Source={StaticResource Locator}, Path=Main}" >
ObservableObject ObservableObject
继承了INotifyPropertyChanged
,主要是简化了属性改变事件的触发
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 public class MainModel : ObservableObject { private int myVar; public int MyProperty { get { return myVar; } set { Set(ref myVar, value ); } } private int _value; public int Value { get { return _value; } set { _value = value ; RaisePropertyChanged("Value" ); } } }
ViewModelBase ViewModelBase
继承了ObservableObject
和Icleanup
接口,自定义的ViewModel可以自己选择是否要继承ViewModelBase,该类中IsInDesignMode
可以用来判断是否属于设计状态中。该类中另一常用的方法是Cleanup虚方法,用于进行资源释放。
资源释放 有时在某个VM中开启一个线程,当关闭View时,对应的VM中的线程仍然不会释放,此时就需要对VM中的线程资源进行释放。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 public class SubWindowVM : ViewModelBase { bool flag = true ; private int myVar; public int MyProperty { get { return myVar; } set { Set(ref myVar, value ); } } public SubWindowVM () { Task.Run(() => { int a = 0 ; while (flag) { Debug.WriteLine($"=========={a++} =========" ); Task.Delay(1000 ).Wait(); } }); } public override void Cleanup () { base .Cleanup(); flag = false ; } }
MvvmLight框架不会自动调用Cleanup方法,需要手动调用。比如当窗体关闭的时候,调用Cleanup方法,当时在View中直接调用VM中的方法违反了MVVM原则。不过,可以利用ViewModelLocator中的静态的Cleanup进行统一的资源释放。
在ViewModelLocator
中定义Cleanup的泛型方法
1 2 3 4 5 6 7 public static void Cleanup <T >() where T:ViewModelBase{ ServiceLocator.Current.GetInstance<T>().Cleanup(); SimpleIoc.Default.Unregister<T>(); SimpleIoc.Default.Register<T>(); }
这样在window的Closed事件中,可以直接调用ViewModelLocator中的Cleanup方法
1 2 3 4 private void Window_Closed (object sender, EventArgs e ){ ViewModelLocator.Cleanup<SubWindowVM>(); }
RelayCommand RelayCommand
继承自ICommand
,用法和RouteCommand类似
1 2 3 4 5 6 7 8 9 10 11 12 13 14 public ICommand BtnCommand{ get => new RelayCommand<string >(obj => { }); } public ICommand MouseCommand{ get => new RelayCommand<object >(obj=> { }); }
Messenger 常规使用 Messenger使用非常灵活,可以在VM中出发,在View中执行逻辑。
在VM中发送
Messenger.Default.Send<int>(123);//广播方式
在View中注册
1 2 Messenger.Default.Register<int >(this ,ReceiveMsg1); private void ReceiveMsg1 (int msg ) {}
如果不想以广播的方式进行发送,可以使用指定token的方式
发送Messenger.Default.Send<int>(123, "M1");//指定Token
注册Messenger.Default.Register<int>(this,"M1",ReceiveMsg2);//指定token
现在有如下需求,要在VM中触发,需要打开一个子窗口,并且还要得到子窗口是否打开的返回值。基于MVVM思想,子窗口属于View层,主窗口才能调用。
1 2 3 4 5 6 7 8 9 public class MessageAction <TValue ,MResult >{ public TValue value { set ; get ; } public Action<MResult> State { set ; get ; } public MessageAction (Action<MResult> state ) { State = state; } }
1 2 3 4 5 6 7 8 9 MessageAction<string , bool > ma = new MessageAction<string , bool >(GetReturn); ma.value = "123" ; Messenger.Default.Send<MessageAction<string , bool >>(ma); private void GetReturn (bool b ){ }
1 2 3 4 5 6 7 8 9 10 11 12 Messenger.Default.Register<MessageAction<string ,bool >>(this , ReceiveMsg); private void ReceiveMsg (MessageAction<string ,bool > msg ){ bool s= new SubWindow().ShowDialog() ==true ; string ss= msg.value ; msg.State.Invoke(s); }
NotificationMessage 发送一个字符串给接受者
1 2 3 4 5 NotificationMessage nm = new NotificationMessage("hello" ); Messenger.Default.Send<NotificationMessage>(nm); Messenger.Default.Register<NotificationMessage>(this , ReceiveNM);
PropertyChangedMessage 传递一个字符串属性名和值发送给接收者,用于将PropertyChanged事件传播给收件人。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 private string _value;public string Value{ get { return _value; } set { _value = value ; Set(ref _value, value ,broadcast:true ); PropertyChangedMessage<string > ddd = new PropertyChangedMessage<string >(Value, _value, "Value" ); Messenger.Default.Send<PropertyChangedMessage<string >>(ddd); Broadcast<string >(Value, _value, "Value" ) } }
DispatcherHelper 1 2 3 4 5 6 DispatcherHelper.Initialize(); DispatcherHelper.CheckBeginInvokeOnUI(); Application.Current.Dispatcher.Invoke()