WPF之MVVM模式(3)

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

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

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

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

  • 在“扩展”中添加“System.Windows.Interractivity”引用.

  • xaml中添加xmlns:i="http://schemas.microsoft.com/expression/2010/interactivity命名空间

  • 使用

    <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如何通信

WPF之MVVM模式(3)

通过一个非常简单的程序来演示这种实现:点击左边的数字,右边的数字加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框架的冲动了。你们有没有?