MVVM Silverlight 4.0 简体中文






4.35/5 (9投票s)
在 Silverlight 4.0 中实现 MVVM 模式
引言
MVVM 是一种基于 MVC/MVP 模式的设计模式,它们都试图解决类似的问题。MVVM 模式旨在分离紧密耦合的 UI 代码,包括渲染、控件操作和数据绑定代码。
为了学习方便,我将代码写得非常简单。我将代码以渐进但完整的方式打包,以便您可以根据需要选择学习的程度。
背景
对于像我这样花了八年时间熟悉“页面后代码”模型的人来说,MVVM 模式最初可能会让人望而生畏。但我很快发现事实并非如此,通过适应这种代码范式的转变,我们可以真正受益匪浅。我想特别感谢 Prabhjot Bakshi 的精彩文章,Brian Pring 用他精彩的演示向我介绍了 Silverlight,以及 Stephen Olah,他积极地促进了我的学习体验。 我希望我学习该模式的经验能对他人有所帮助。
MVVM 概念
MVVM 模式包含 3 个部分
- 视图
- ViewModel
- 模型
视图绑定到 ViewModel,模型中的任何更改都会自动反映在视图中。ViewModel 将处理模型中的任何更改,并接收视图上触发的事件。是的,就是这么简单!

第一部分
在这里,我想介绍 MVVM 模式的基本概念,它有助于将 UI 代码逻辑上分离为 View(视图)、ViewModel(视图模型)和 Model(模型)。
视图
View 包含渲染 Silverlight 应用程序 UI 的代码,其中将包含您的 XAML 代码。理想情况下,要真正实现 MVVM 模式,我们希望避免任何代码隐藏。这意味着我们需要在 XAML 中将 View 连接到 ViewModel。您需要特别注意此部分细节,因为这可以为您节省大量调试时间。
首先,我在 `UserControl` 属性列表中注册 `ViewModel` 命名空间。
xmlns : local ="clr-namespace:MVVMApp.ViewModel"
在我的视图中,我有一个外部的 `Grid`,我将其连接到我的 `ViewModel`
<grid.datacontext>
<local:contactviewmodel>
</local:contactviewmodel></grid.datacontext>
然后有一个内部的 `Grid`,我将其绑定到模型的一个实例
<Grid DataContext="{Binding Path=mycontact}">
最后,将属性绑定到实际渲染我的文本/数据的控件。
<textbox grid.row="0" text="{Binding Path=FirstName }">
<textbox grid.row="1" text="{Binding Path=SecondName }">
</textbox></textbox>
ViewModel
这是棘手的部分,将 `ViewModel` 视为一个连接到模型的专用代理。在 ASP.NET 中,您可以将其视为代码隐藏,您将在其中处理事件代码和数据绑定。
public class ContactViewModel
{
public Contact mycontact { get; set; }
public ContactViewModel()
{
Contact cont = new Contact();
cont.FirstName = "Ritesh";
cont.SecondName = "Ramesh";
mycontact = cont;
}
}
模型
将 Model 视为包含数据的结构。Model 不会实现任何功能。但是,要在 MVVM 模式中使用 Model,我们需要 Model 实现 `INotifyPropertyChanged` 接口。`INotifyPropertyChanged` 接口用于通知客户端(通常是绑定客户端),属性值已更改。
我的模型有两个属性 `FirstName` 和 `SecondName`,并实现了 `INotifyPropertyChanged` 接口。`NotifyPropertyChanged` 方法检查属性是否有效,并向我的视图通知属性更改。
public class Contact : INotifyPropertyChanged
{
private string _FirstName;
public string FirstName {
get { return _FirstName; }
set { _FirstName = value;
NotifyPropertyChanged("FirstName");
}
}
private string _SecondName;
public string SecondName {
get { return _SecondName; }
set { _SecondName = value;
NotifyPropertyChanged("SecondName");
}
}
public event PropertyChangedEventHandler PropertyChanged;
private void NotifyPropertyChanged(String info)
{
if (PropertyChanged != null)
{
PropertyChanged(this, new PropertyChangedEventArgs(info));
}
}
}
第二部分
在这里,我想进入 MVVM 模式的下一个阶段。即使用按钮控件实现命令,该命令将触发 ViewModel 中 View 和 Model 之间的自动数据绑定。
视图
我在 View 的现有 XAML 中添加了以下按钮语法。
<Button Grid.Row="2" Command="{Binding Path=DataContext.GetContact ,
ElementName= LayoutRoot }" Content="View"
CommandParameter="{Binding Path=Phone}" />
ViewModel
这是实现按钮执行的大部分更改的地方。
在我的 ViewModel 中,我引入了一个 `GenericCommand` 类,它实现了 `ICommand` 接口,公开了 `CanExecute`、`Execute` 方法和一个 `CanExecuteChanged` 事件。
- `CanExecute` - 在这里,您可以实现任何需要在调用执行之前检查的验证代码。在我的代码中,我将其设置为始终返回 `true`。
- `Execute` - 在这里,您可以实现按钮单击事件上需要执行的任何代码。
- `CanExecuteChanged` - 当影响命令是否应执行的更改发生时触发。
public class GenricCommand : ICommand
{
ContactViewModel _vm;
public GenricCommand( ContactViewModel vm)
{
_vm = vm;
}
public bool CanExecute(object parameter)
{
return true ;
}
public event EventHandler
CanExecuteChanged;
public void Execute( object
parameter)
{
_vm.showContact( );
}
}
此外,我还修改了我的 `ViewModel` 类,添加了一个名为 `GetContact` 的方法,该方法返回我的 `GenricCommand` 类的一个对象。
public ICommand GetContact
{
get { return new GenricCommand(this); }
}
这反过来会将按钮单击执行的代码委托给我的 ViewModel 中包含的 `showContact` 方法。
public void showContact()
{
mycontact.FirstName = "Ritesh";
mycontact.SecondName = "Ramesh";
}
模型
我的模型不需要任何更改。
关注点
- 这只是 MVVM 模式的一种实现方式,还有许多其他方法可以实现相同的功能。
- ViewModel 到底应该包含什么仍然非常有争议,例如,我应该在 View 本身中实现 `datagrid` 的排序,还是需要在 ViewModel 中实现该功能对我来说仍然是个谜?