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的


评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值