• MvvmLight框架使用入门(四)


      本篇我们着重介绍ViewModelBase,演示SetRaisePropertyChanged方法的使用,以及就Cleanup方法释放资源展开讨论。

    ICleanup

    接口。实现该接口的ViewModel需要在Cleanup方法里释放资源,特别是-= event

    ObservableObject

    该类实现了INotifyPropertyChanged接口,定义了一个可通知的对象基类,供ViewModelBase继承

    ViewModelBase

    继承自ObservableObject,   ICleanup。将作为MvvmLight框架下使用的ViewModel的基类。主要提供Set和RaisePropertyChanged供外部使用。同时会在Cleanup方法里,Unregister该实例的所有的MvvmLight Messenger(在GalaSoft.MvvmLight.Messaging命名空间定义)

      以上是第一篇里给出的表格,ViewModelBaseMvvmLight里非常重要的一个基类,理论上使用MvvmLight你所有的ViewModel都需要继承该类(当然你也可以不继承,那你还用啥MvvmLight?啥?只用RelayCommand?给跪了……)

      我们先看一下最基本的SetRaisePropertyChanged方法的使用:

            private string title;
    
            public string Title
            {
                get { return title; }
                set { Set(ref title , value); }
            }
    
            private string text;
    
            public string Text
            {
                get { return text; }
                set
                {
                    text = value;
                    RaisePropertyChanged("Text");
                    RaisePropertyChanged("TitleAndText");
                }
            }
    
            public string TitleAndText
            {
                get
                {
                    return title + text;
                }
            }

      Set方法会再属性赋值时自动为你调用RaisePropertyChanged进行通知。当然你也可以手动调用RaisePropertyChanged方法。

      MvvmLight的源代码如下,将可复用的逻辑提取封装,减少了我们搬砖时的工作量:

            protected bool Set<T>(
                ref T field,
                T newValue = default(T),
                bool broadcast = false,
                [CallerMemberName] string propertyName = null)
            {
                if (EqualityComparer<T>.Default.Equals(field, newValue))
                {
                    return false;
                }
    #if !PORTABLE
                RaisePropertyChanging(propertyName);
    #endif
                var oldValue = field;
                field = newValue;
    
                RaisePropertyChanged(propertyName, oldValue, field, broadcast);
    return true;
            }

      Cleanup是一个非常重要的方法。当前PageOnNavigatedFrom时,应该要释放不再需要的资源,特别是-= event,Unregister掉MvvmLightMessenger

      在继承ViewModelBase的子类ViewModel里调用base.Cleanup();会自动释放掉当前ViewModel注册的Messenger

      ViewModelBase里的Cleanup方法:

            public virtual void Cleanup()
            {
                MessengerInstance.Unregister(this);
            }

      所以一般ViewModelOnNavigatedFrom方法看上去都是这个样子:

            public void OnNavigatedFrom(object obj)
            {
                base.Cleanup();
                this.xxxxEvent -= xxxxHandler;
            }

      什么什么,你说ViewModel是没有OnNavigatedFrom方法的?确实是没有的,但是我们这里给需要处理导航事件的ViewModel都实现了INavigable接口:

        public interface INavigable
        {
            void OnNavigatedFrom(object obj);
    
            void OnNavigatedTo(object obj);
        }

      然后呢,override需要处理导航事件的Page的相应方法,调用ViewModel里的NavigatedFromNavigatedTo方法,传递参数,把处理的逻辑放到ViewModel中:

        public sealed partial class MainPage : Page
        {
            public MainPage()
            {
                this.InitializeComponent();
            }
    
            protected override void OnNavigatedTo(NavigationEventArgs e)
            {
                base.OnNavigatedTo(e);
                var navigable = DataContext as INavigable;
                navigable.OnNavigatedTo(e.Parameter);
            }
    
            protected override void OnNavigatedFrom(NavigationEventArgs e)
            {
                base.OnNavigatedFrom(e);
                var navigable = DataContext as INavigable;
                navigable.OnNavigatedFrom(e.Parameter);
            }
        }

      看到这里,是不是觉得释放资源什么的也是一件非常的简单的事情呢?但是骚年!Too young too simple, sometimes naive!仅仅这样就够了吗?我们需要再回到Cleanup方法,既然ViewModel可以通过OnNavigatedFrom来释放资源,但如果ViewModel并没有,或者说不需要导航事件,又该如何处理呢。例如某个MainPage对应的MainViewModel中存在一个ContactViewModel的列表:

        public class MainViewModel : ViewModelBase, INavigable
        {
            ObservableCollection<ContactViewModel> ContactList { get; set; }

      ContactViewModel仅仅是对Contact数据对象做的封装,并不存在导航事件。这时候,如果不需要ContactList常驻内存,MainViewModel的OnNavigatedFrom方法就长成这样了:

            public void OnNavigatedFrom(object obj)
            {
                base.Cleanup();
                this.xxxxEvent -= xxxxHandler;
    
                foreach (var contact in ContactList)
                {
                    contact.Cleanup();
                }
                ContactList.Clear();
            }

      没有错哦,仍然是继承了ViewModelBaseContactViewModel自己来释放内部的资源,但是Cleanup的调用是由外部引用ContactListMainViewModel来发起的。

      本篇就ViewModelBase的继承使用展开了讨论,介绍了一点俺平时使用的经验,包括如何使用导航事件和释放资源。还希望能给萌新们启发,老司机们轻拍。

      另外MvvmLight框架使用入门系列可能会暂停一下(反正也没人看……),因为俺接下来要开始搞Win10Universal App了,挖咔咔!

     

     

  • 相关阅读:
    批处理学习总结之常用命令1
    Delphi常用数据类型
    Delphi预编译指令总结
    Delphi同步互斥总结
    MyEclipse 环境配置总结
    倒排索引
    laravel 学习相关笔记
    elasticsearch倒排索引原理
    原生sql和 TP sql怎么关联?
    elastic
  • 原文地址:https://www.cnblogs.com/manupstairs/p/4948347.html
Copyright © 2020-2023  润新知