zoukankan      html  css  js  c++  java
  • 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框架的冲动了。你们有没有?

  • 相关阅读:
    HTTP断点续传 规格严格
    Java Shutdown 规格严格
    linux 命令源码 规格严格
    JTable调整列宽 规格严格
    linux 多CPU 规格严格
    Hello can not find git path 规格严格
    Kill 规格严格
    拜拜牛人 规格严格
    Swing 规格严格
    Debugging hangs in JVM (on AIX but methodology applicable to other platforms) 规格严格
  • 原文地址:https://www.cnblogs.com/igotogo/p/5401112.html
Copyright © 2011-2022 走看看