你的位置:首页 > ASP.net教程

[ASP.net教程]WPF之MVVM模式(3)


有种想写一个MVVM框架的冲动!!!

 

1、Model中的属性应不应该支持OnPropertyChanged事件?


不应该。应该有ViewModel对该属性进行封装,由ViewModel提供OnPropertyChanged事件。 WPF之MVVM(1)中有实例

 

2、如何将控件事件转换为命令?


 

  • 在“扩展”中添加“System.Windows.Interractivity”引用
  • xaml中添加命名空间
  • 使用

    <ListBox Name="LbBox" ItemsSource="{Binding Path=SourceCount}">  <i:Interaction.Triggers>    <i:EventTrigger EventName="SelectionChanged">      <common:ExInvokeCommandAction Command="{Binding Path=SelectionChangedCmd}" CommandParameter="{Binding ElementName=LbBox, Path=SelectedItem}"/>    </i:EventTrigger>  </i:Interaction.Triggers></ListBox>

     

3、View中如何访问ViewModel


 WPF之MVVM(2)中介绍了

 

4、ViewModel中如何访问View


 WPF之MVVM(2)中介绍了

 

5、ViewModel之间通信


 

  • 聚合关系

    public class VM01{  public string Name{get;set;}}public class VM02{  public list<VM01> Property  {    get;    set;  }}

     

  • 组合关系

    public class VM01{  public string Name{get;set;}}public class VM02{  public string Name{get;set;}}public class VM03{  private VM01 _vm01;  private VM02 _vm02;  ...  public VM03(VM01 vm01, VM02 vm02){}}

     

  • 依赖关系

这里主要介绍下依赖关系的ViewModel如何通信

通过一个非常简单的程序来演示这种实现:点击左边的数字,右边的数字加1。

左边为LeftViewModel右边为RightViewModel,两个VM是相互独立的,通过事件进行通信。

1、定义类型来容纳所有需要发送给事件通知接收者的附件信息

public class NumberChangedEventArgs : EventArgs{  public int Number { get; set; }  public NumberChangedEventArgs(int num)  {    Number = num;  }}

 

2、在LeftViewModel中定义事件成员

public event EventHandler<NumberChangedEventArgs> NumberChanged;protected virtual void OnNumberChanged(NumberChangedEventArgs e){  var handler = NumberChanged;  if (handler != null) handler(this, e);}

 

3、定义负责引发事件的方法来通知事件的登记对象

/// <summary>/// 选择命令/// </summary>private DelegateCommand<ExCommandParameter> _selectionChangedCmd;public DelegateCommand<ExCommandParameter> SelectionChangedCmd{  get  {    if (_selectionChangedCmd == null)    {      _selectionChangedCmd = new DelegateCommand<ExCommandParameter>(InvokeMouseDown);    }    return _selectionChangedCmd;  }}private void InvokeMouseDown(ExCommandParameter param){  var number = param.Parameter is int ? (int) param.Parameter : 0;  //触发事件  OnNumberChanged(new NumberChangedEventArgs(number));}

 

4、定义方法将输入转化为期望事件

public class RightViewModel : ViewModelBase{  public RightViewModel()  {    //订阅事件    var vm = ViewModelManager.GetByKey("left") as LeftViewModel;    if (vm != null) vm.NumberChanged += VmOnNumberChanged;  }  private int _number;  public int Number  {    get { return _number; }    set    {      _number = value;      OnPropertyChanged("Number");    }  }  /// <summary>  /// 事件处理  /// </summary>  /// <param name="sender"></param>  /// <param name="e"></param>  private void VmOnNumberChanged(object sender, NumberChangedEventArgs e)  {    Number = e.Number + 1;  }}

 

问题RightViewModel中如何获取LeftViewModel呢?

定义一个容器

public static class ViewModelManager{  private static readonly Dictionary<string, ViewModelBase> Dic = new Dictionary<string, ViewModelBase>();  public static void Add(string key, ViewModelBase value)  {    if (Dic.ContainsKey(key)) return;    Dic.Add(key, value);  }  public static ViewModelBase GetByKey(string key)  {    if (!Dic.ContainsKey(key)) return null;    ViewModelBase value;    Dic.TryGetValue(key, out value);    return value;  }}

 

在设置View的DataContext时将ViewModel添加到ViewModelManager

public LeftView(){  InitializeComponent();  var vm = new LeftViewModel();  ViewModelManager.Add("left", vm);  this.DataContext = vm;}

 

总结


 回顾上面3篇博文中解决的问题,我们再来看下MvvmLight ToolKit是如何实现MVVM的,这里引用下园友的总结MvvmLight ToolKit 教程。

我们可以猜测MvvmLight作者使用这些组件是为了解决什么问题?

  • ViewModelBase && ObservableObject(INotifyPropertyChanged接口的实现,解决属性改变通知的问题)
  • ViewModelLocator && SimpleIoc(IOC容器,我们的ViewModelManager高级版)
  • RelayCommand(ICommand接口的实现,解决View和ViewModel通信问题)
  • EventToCommand && IEventArgsConverter(Interaction的封装,解决将事件转换为命令的问题)
  • Messenger(解决View和ViewModel以及ViewModel和ViewModel之间通信的问题)
  • DispatcherHelper(博客中未提到)

这样分析后,我们就知道MvvmLight是如何产生的,以及它能为我们做什么。

吹牛吹到现在,我都有种自己想写一个MVVM框架的冲动了。你们有没有?