MVVM 設計模式中的控件加載、卸載


在MVVM設計中,如果遇到界面打開時需要讀取數據庫數據,此爲耗時操作,我又有潔癖,不想把這段代碼寫到ViewMoel的構造函數中。

於是便有了下面的解決方案!

靈感來源與設計模式中的橋接模式,使得界面的ViewModel和Control的ViewModel獨立變化

首先是在項目中此次用到的控件功能,只有加載和卸載的功能,加載時提供數據,卸載時清理數據。

設計接口的UML如下:

IControlViewModel

3個屬性,2個事件,MVVM模式中,View和ViewModel的數據交換主要是靠Bingding,而交互主要是靠 命令 Command,所以在此接口中設計了加載命令和LoadedCommand和卸載命令UnloadedCommand,以及這兩個命令執行時所觸發的事件Loaded和Unloaded。接口代碼實現如下:

/// <summary>
    /// The ControlViewModel interface.
    /// </summary>
    public interface IControlViewModel
    {
        /// <summary>
        /// The loaded event.
        /// </summary>
        event EventHandler Loaded;

        /// <summary>
        /// The unloaded event.
        /// </summary>
        event EventHandler Unloaded;

        /// <summary>
        /// Gets the loaded command.
        /// </summary>
        ICommand LoadedCommand { get; }

        /// <summary>
        /// Gets the unloaded command.
        /// </summary>
        ICommand UnloadedCommand { get; }

        /// <summary>
        /// Gets or sets the title.
        /// </summary>
        string Title { get; set; }
    }

ControlViewModel 爲IControlViewModel結構實現類,繼承自ViewModelBase(注1),實現代碼如下:

/// <summary>
    /// The control view model.
    /// </summary>
    public class ControlViewModel : ViewModelBase, IControlViewModel
    {
        #region Fields

        /// <summary>
        /// The title.
        /// </summary>
        private string title;

        #endregion

        #region Constructors

        /// <summary>
        /// Initializes a new instance of the <see cref="ControlViewModel"/> class.
        /// </summary>
        public ControlViewModel()
        {
            this.LoadedCommand = new RelayCommand(this.OnLoaded);

            this.UnloadedCommand = new RelayCommand(this.OnUnloaded);
        }

        #endregion

        #region Events

        /// <summary>
        /// The loaded.
        /// </summary>
        public event EventHandler Loaded;

        /// <summary>
        /// The unloaded.
        /// </summary>
        public event EventHandler Unloaded;

        #endregion

        #region Commands

        /// <summary>
        /// Gets the loaded command.
        /// </summary>
        public ICommand LoadedCommand { get; private set; }

        /// <summary>
        /// Gets the unloaded command.
        /// </summary>
        public ICommand UnloadedCommand { get; private set; }

        #endregion

        #region Properteis

        /// <summary>
        /// Gets or sets the title.
        /// </summary>
        public string Title
        {
            get
            {
                return this.title;
            }

            set
            {
                this.title = value;
                this.RaisePropertyChanged("Title");
            }
        }

        #endregion

        #region Methods

        /// <summary>
        /// The on loaded.
        /// </summary>
        private void OnLoaded()
        {
            var loaded = this.Loaded;
            if (loaded != null)
            {
                loaded(this, new EventArgs());
            }
        }

        /// <summary>
        /// The on unloaded.
        /// </summary>
        private void OnUnloaded()
        {
            var unloaded = this.Unloaded;
            if (unloaded != null)
            {
                unloaded(this, new EventArgs());
            }
        }

        #endregion
    }

可以清楚的看到在構造函數中初始化兩個命令的時候,這兩個命令分別觸發了加載Loaded和卸載Unloaded的事件.


那麼,它們是怎麼工作的呢?如何當頁面加載的時候就去執行LoadedCommand命令呢?請繼續往下看:

首先,我們要在界面的項目工程中引入 System.Windows.Interactivity.dll 程序集。

然後,在界面中,添加如下代碼:

<i:Interaction.Triggers>
        <i:EventTrigger EventName="Loaded">
            <i:InvokeCommandAction 
                Command="{Binding ControlViewModel.LoadedCommand}">
            </i:InvokeCommandAction>
        </i:EventTrigger>
        <i:EventTrigger EventName="Unloaded">
            <i:InvokeCommandAction 
                Command="{Binding ControlViewModel.UnloadedCommand}">
            </i:InvokeCommandAction>
        </i:EventTrigger>
    </i:Interaction.Triggers>

通過觸發器將事件綁定到命令,當Loaded事件加載時,會執行ControlViewModel屬性的LoadedCommand命令,當Unloaded事件被觸發時,會執行ControlViewModel屬性的UnloadedCommand命令。

界面的ViewModel代碼如下:

    public class MainViewModel: ViewModelBase
    {
        /// <summary>
        /// Initializes a new instance of the <see cref="InstrumentCorrectVm"/> class.
        /// </summary>
        public MainViewModel()
        {
            this.ControlViewModel = new ControlViewModel();
            this.ControlViewModel.Loaded += this.ControlViewModelLoaded;
            this.ControlViewModel.Unloaded += (o, args) => this.Cleanup();
            
        }

        /// <summary>
        /// Gets the control view model.
        /// </summary>
        public IControlViewModel ControlViewModel { get; private set; }

        /// <summary>
        /// The control view model_ loaded.
        /// </summary>
        /// <param name="sender">
        /// The sender.
        /// </param>
        /// <param name="e">
        /// The e.
        /// </param>
        private void ControlViewModelLoaded(object sender, EventArgs e)
        {
             //TODO : 加載數據
        }

    }





注: 此處是第一篇關於MVVM模式的文章,有關MVVM的基礎知識,可以通過百度後者GOOGLE可以查閱,本文不做詳解。

        本文是基於MVVMLight框架設計的,對於如何使用MVVMLight框架的,本文不做詳解,如有感興趣的,可參考:點擊打開鏈接

        本人QQ:351157970.歡迎討論!

注1:該類在MVVMLight中,使用的MVVM模式是基於MVVMLight的


發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章