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

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

时间: 2024-10-13 17:18:46

WPF之MVVM模式(3)的相关文章

浅析WPF中MVVM模式下命令与委托的关系

??各位朋友大家好,我是Payne,欢迎大家关注我的博客,我的博客地址是http://qinyuanpei.com.最近因为项目上的原因开始接触WPF,或许这样一个在现在来讲显得过时的东西,我猜大家不会有兴趣去了解,可是你不会明白对某些保守的项目来讲,安全性比先进性更为重要,所以当你发现银行这类机构还在使用各种"复古"的软件系统的时候,你应该相信这类东西的确有它们存在的意义.与此同时,你会更加深刻地明白一个道理:技术是否先进性和其流行程度本身并无直接联系.由此我们可以推论出:一项不流行

【WPF】MVVM模式的3种command

原文:[WPF]MVVM模式的3种command 1.DelegateCommand 2.RelayCommand 3.AttachbehaviorCommand 因为MVVM模式适合于WPF和SL,所以这3种模式中也有一些小差异,比如RelayCommand下面的CommandManager方法就是WPF下面的,SL下面无法使用,不过我认为这3种方法中的基本思路都如出一辙,都是出自那位外国牛人的文章里面.主要的区别在于和VIEW中的控件的绑定使用上.有点不同的attachbehaviorcom

WPF之MVVM模式(2)

我们都想追求完美 Every view in the app has an empty codebehind file, except for the standard boilerplate code that calls InitializeComponent in the class's constructor. In fact, you could remove the views' codebehind files from the project and the applicatio

【转】【WPF】MVVM模式的3种command

1.DelegateCommand 2.RelayCommand 3.AttachbehaviorCommand 因为MVVM模式适合于WPF和SL,所以这3种模式中也有一些小差异,比如RelayCommand下面的CommandManager方法就是WPF下面的,SL下面无法使用,不过我认为这3种方法中的基本思路都如出一辙,都是出自那位外国牛人的文章里面.主要的区别在于和VIEW中的控件的绑定使用上.有点不同的attachbehaviorcommand是prism4里面的一种设计模式,这个区别

WPF采用MVVM模式(绑定:纯前台、命令:触发器绑定命令)

MVVM绑定 view-viewModel-model,模型介绍省略,就是创建类,添加字段封装属性.注:控件的绑定只能绑定到属性上,不能绑定到字段上: 接下来就是代码 (view): 1 <Window x:Class="WpfBing.MainWindow" 2 xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation" 3 xmlns:x="http://schemas.mi

笔记03 wpf 在MVVM模式下怎样在Viewmodel里面获得view的控件对象

 转自http://blog.csdn.net/qing2005/article/details/6601199http://blog.csdn.net/qing2005/article/details/6601475 MVVM中轻松实现Command绑定(二)传递Command参数 属性栏里去设置的.语句应该是CommandParameter="{Binding ElementName=控件名}" 我们如果需要在Command中传递参数,实现也很简单.DelegateCommand还

WPF:MVVM模式下ViewModel关闭View

不外乎两种基本方法. 消息通知和参数传递. 一.消息通知 利用View里的IsEnable属性 原理是这样的: 1.UI中的IsEnabled绑定VM中的属性 2.UI的后台代码中,注册IsEnableChange事件,在这个事件里,检测到传过来的值满足某个条件,即可触发Close()命令 如此,VM控制自己那个属性就能达到关闭V的目的了. 二.参数传递. 根据参数传递的不同.分为传递函数和传递View对象. 1传递函数 该方法:需要三步. 1.重写ViewModel的构造函数 public P

Wpf DataGrid MVVM模式实现双击

Instead of double-clicking on the cell you may double-click on the grid 1 <DataGrid.InputBindings> 2 <MouseBinding Gesture="LeftDoubleClick" Command="{Binding Edit}" CommandParameter="{Binding ElementName=UsersDataGrid, P

WPF 在MVVM模式下弹出子窗体的方式

主要是通过一个WindowManager管理类,在window后台代码中通过WindowManager注册需要弹出的窗体类型,在ViewModel通过WindowManager的Show方法,显示出来. WindowManager代码如下: public static class WindowManager { private static Hashtable _RegisterWindow = new Hashtable(); public static void Regiter<T>(st