码迷,mamicode.com
首页 > Windows程序 > 详细

WPF之MVVM模式(3)

时间:2016-04-17 16:05:21      阅读:258      评论:0      收藏:0      [点我收藏+]

标签:

有种想写一个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如何通信

技术分享

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

WPF之MVVM模式(3)

标签:

原文地址:http://www.cnblogs.com/igotogo/p/5401112.html

(0)
(0)
   
举报
评论 一句话评论(0
登录后才能评论!
© 2014 mamicode.com 版权所有  联系我们:gaon5@hotmail.com
迷上了代码!