Getting started with the MvvmLight framework

MvvmLight

MvvmLight main library

image-20230220151724416

ViewModelLocator

The nuget installation in the .netFramework environment MvvmLightwill automatically install the dependency MvvmLightLibslibrary, if you need to manually install the library in the .net core environment MvvmLightLibs.

After the installation is completed in the .netFramework environment, there is a class in the ViewModel directory ViewModelLocator, which is used to provide dependency injection containers and related properties.

public class ViewModelLocator
{
    
    
    public ViewModelLocator()
    {
    
    
        ServiceLocator.SetLocatorProvider(() => SimpleIoc.Default);

        //判断是否为设计时
        //if (ViewModelBase.IsInDesignModeStatic)
        SimpleIoc.Default.Register<MainViewModel>();//注册MainViewModel
        SimpleIoc.Default.Register<SubWindowVM>();//注册SubWindowVM
    }

    public MainViewModel Main
    {
    
    
        get
        {
    
    	//返回MainViewModel实例,必须在前面进行注册后才可以
            return ServiceLocator.Current.GetInstance<MainViewModel>();
        }
    }

    public SubWindowVM SubWin
    {
    
    
        get
        {
    
    
            return ServiceLocator.Current.GetInstance<SubWindowVM>();
        }
    }

    public static void Cleanup(){
    
    }
}

ViewModelLocatorIn addition, add resources to App.xaml

<Application.Resources>
    <ResourceDictionary>
        <vm:ViewModelLocator  x:Key="Locator" />
    </ResourceDictionary>
</Application.Resources>

In this way, the DataContext can be registered in MainWindow like this

<Window DataContext="{Binding Source={StaticResource Locator}, Path=Main}">

ObservableObject

ObservableObjectInherited INotifyPropertyChanged, mainly to simplify the triggering of property change events

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

ViewModelBaseInherited ObservableObjectand Icleanupinterface, the custom ViewModel can choose whether to inherit ViewModelBase, which IsInDesignModecan be used to judge whether it belongs to the design state. Another commonly used method in this class is the Cleanup virtual method, which is used for resource release.

resource release

Sometimes a thread is started in a certain VM, and when the View is closed, the thread in the corresponding VM will still not be released. At this time, the thread resources in the VM need to be released.

public class SubWindowVM : ViewModelBase
{
    
    
    bool flag = true;

    private int myVar;

    public int MyProperty
    {
    
    
        get {
    
     return myVar; }
        set {
    
     Set(ref myVar, value); }//效果相同
        //set { myVar = value; RaisePropertyChanged(); }
    }
    public SubWindowVM()
    {
    
    
        Task.Run(() =>
        {
    
    
            int a = 0;
            while (flag)
            {
    
    
                Debug.WriteLine($"=========={
      
      a++}=========");
                Task.Delay(1000).Wait();
            }
        });
    }
    //需要明确调用
    //释放VM中的资源,如线程,如果不调用,线程无法停止
    //瞬时模式,每次调用后需要清理
    public override void Cleanup()
    {
    
    
        base.Cleanup();
        flag = false;
    }
}

The MvvmLight framework does not automatically call the Cleanup method and needs to be called manually. For example, when the form is closed, the Cleanup method is called. At that time, calling the method in the VM directly in the View violates the MVVM principle. However, you can use the static Cleanup in ViewModelLocator for unified resource release.

ViewModelLocatorThe generic method for Cleanup is defined in

public static void Cleanup<T>() where T:ViewModelBase
{
    
    
    ServiceLocator.Current.GetInstance<T>().Cleanup();//释放资源

    SimpleIoc.Default.Unregister<T>();//释放对象
    SimpleIoc.Default.Register<T>();//为下次打开可以用
}

In this way, in the Closed event of the window, the Cleanup method in the ViewModelLocator can be called directly

private void Window_Closed(object sender, EventArgs e)
{
    
    
    ViewModelLocator.Cleanup<SubWindowVM>();
}

RelayCommand

RelayCommandInherited from ICommand, usage is similar to RouteCommand

public ICommand BtnCommand
{
    
    
    //get => new RelayCommand(() => { });
    //带参数
    get => new RelayCommand<string>(obj =>
    {
    
     });
    //如果泛型定义为int则会转换失效,这里的泛型一般是引用,不能是值类型,因为用的反射机制
}
//任意事件的处理
public ICommand MouseCommand
{
    
    
    get => new RelayCommand<object>(obj=>
    {
    
     });
}

Messenger

regular use

Messenger is very flexible to use and can start in VM and execute logic in View.

send in VM

Messenger.Default.Send<int>(123);//广播方式

Register in View

Messenger.Default.Register<int>(this,ReceiveMsg1);//广播方式
private void ReceiveMsg1(int msg){
    
    }

If you don't want to send by broadcast, you can use the way of specifying token

  • sendMessenger.Default.Send<int>(123, "M1");//指定Token
  • registerMessenger.Default.Register<int>(this,"M1",ReceiveMsg2);//指定token

Now there is the following requirement, to trigger in the VM, you need to open a sub-window, and also get the return value of whether the sub-window is open. Based on the idea of ​​MVVM, the sub-window belongs to the View layer and can only be called by the main window.

  • Create a new class MessageAction
public class MessageAction<TValue,MResult>
{
    
    
     public TValue value {
    
     set; get; }
     public Action<MResult> State {
    
     set; get; }
     public MessageAction(Action<MResult> state)
     {
    
    
         State = state;
     }
}
  • MainWindow
MessageAction<string, bool> ma = new MessageAction<string, bool>(GetReturn);
ma.value = "123";
Messenger.Default.Send<MessageAction<string, bool>>(ma);

//可以得到返回值
private void GetReturn(bool b)
{
    
    

}
  • MainViewModel
Messenger.Default.Register<MessageAction<string,bool>>(this, ReceiveMsg);


private void ReceiveMsg(MessageAction<string,bool> msg)
{
    
    
    bool s=  new SubWindow().ShowDialog() ==true;//此时需要得到ShowDialog的返回值,true、false
    //使用委托来实现返回值给发送消息者
    string ss= msg.value;
    msg.State.Invoke(s);
    //为什么这样做,因为动作的触发点在VM中,VM中做触发的时候需要进行状态判断,也就是需要有返回值
    //需要View中进行窗口操作,并且返回状态
}

NotificationMessage

send a string to the receiver

//触发
NotificationMessage nm = new NotificationMessage("hello");
Messenger.Default.Send<NotificationMessage>(nm);
//注册
Messenger.Default.Register<NotificationMessage>(this, ReceiveNM);

PropertyChangedMessage

Pass a string property name and value to send to the recipient for propagating the PropertyChanged event to the recipient.

private string _value;

public string Value
{
    
    
    get {
    
     return _value; }
    set
    {
    
    
        _value = value;
        //有两种方式发送PropertyChangedMessage
        //1.broadcast:true
        Set(ref _value, value,broadcast:true);
        //2.Messenger.Default.Send
        PropertyChangedMessage<string> ddd = new PropertyChangedMessage<string>(Value, _value, "Value");
        Messenger.Default.Send<PropertyChangedMessage<string>>(ddd);
        //3.使用Broadcast
        Broadcast<string>(Value, _value, "Value")
    }
}

DispatcherHelper

//多线程,先检查是否在UI线程,如果不在则把该线程挂上去
//不能直接使用,需要配套
DispatcherHelper.Initialize();//一般把这一句写在App对象中
DispatcherHelper.CheckBeginInvokeOnUI()//异步的
//这样也可以
Application.Current.Dispatcher.Invoke()

Guess you like

Origin blog.csdn.net/weixin_44064908/article/details/129140450