在MVVM设计中,如果遇到界面打开时需要读取数据库数据,此为耗时操作,我又有洁癖,不想把这段代码写到ViewMoel的构造函数中。
于是便有了下面的解决方案!
灵感来源与设计模式中的桥接模式,使得界面的ViewModel和Control的ViewModel独立变化
首先是在项目中此次用到的控件功能,只有加载和卸载的功能,加载时提供数据,卸载时清理数据。
设计接口的UML如下:
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的