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了,挖咔咔!

 

 

 

 


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM