WPF的MVVM设计模式

从winform转变到WPF的过程,难点主要还是在MVVM的设计模式。当然,如果依然采用winform的涉及方式,在每个控件背后绑定事件的方式运用在wpf中,依然可行,但是假如GUI改版,其背后绑定的特别为此界面设计的事件不得不多数弃用。而MVVM最大的好处是将一切业务逻辑放在ViewModel中 ,将GUI的操作放在view中,将数据结构放在Model中,如图摘自MSDN

实际使用

使用了Prism框架,省去了去构造实现INotifyPropertyChanged的基类,直接继承BindableBase

namespace Prism.Mvvm{    //    // 摘要:    //     Implementation of System.ComponentModel.INotifyPropertyChanged to simplify models.    public abstract class BindableBase : INotifyPropertyChanged    {        protected BindableBase();        //        // 摘要:        //     Occurs when a property value changes.        public event PropertyChangedEventHandler PropertyChanged;        //        // 摘要:        //     Notifies listeners that a property value has changed.        //        // 参数:        //   propertyName:        //     Name of the property used to notify listeners. This value is optional and can        //     be provided automatically when invoked from compilers that support System.Runtime.CompilerServices.CallerMemberNameAttribute.        protected virtual void OnPropertyChanged([CallerMemberName] string propertyName = null);        //        // 摘要:        //     Raises this object's PropertyChanged event.        //        // 参数:        //   propertyExpression:        //     A Lambda expression representing the property that has a new value.        //        // 类型参数:        //   T:        //     The type of the property that has a new value        protected virtual void OnPropertyChanged<T>(Expression<Func<T>> propertyExpression);        //        // 摘要:        //     Checks if a property already matches a desired value. Sets the property and notifies        //     listeners only when necessary.        //        // 参数:        //   storage:        //     Reference to a property with both getter and setter.        //        //   value:        //     Desired value for the property.        //        //   propertyName:        //     Name of the property used to notify listeners. This value is optional and can        //     be provided automatically when invoked from compilers that support CallerMemberName.        //        // 类型参数:        //   T:        //     Type of the property.        //        // 返回结果:        //     True if the value was changed, false if the existing value matched the desired        //     value.        protected virtual bool SetProperty<T>(ref T storage, T value, [CallerMemberName] string propertyName = null);    }

以及用来构造Command的基类DelegateCommand

namespace Prism.Commands{    //    // 摘要:    //     An System.Windows.Input.ICommand whose delegates do not take any parameters for    //     Prism.Commands.DelegateCommand.Execute and Prism.Commands.DelegateCommand.CanExecute.    public class DelegateCommand : DelegateCommandBase    {        //        // 摘要:        //     Creates a new instance of Prism.Commands.DelegateCommand with the System.Action        //     to invoke on execution.        //        // 参数:        //   executeMethod:        //     The System.Action to invoke when System.Windows.Input.ICommand.Execute(System.Object)        //     is called.        public DelegateCommand(Action executeMethod);        //        // 摘要:        //     Creates a new instance of Prism.Commands.DelegateCommand with the System.Action        //     to invoke on execution and a Func to query for determining if the command can        //     execute.        //        // 参数:        //   executeMethod:        //     The System.Action to invoke when System.Windows.Input.ICommand.Execute(System.Object)        //     is called.        //        //   canExecuteMethod:        //     The System.Func`1 to invoke when System.Windows.Input.ICommand.CanExecute(System.Object)        //     is called        public DelegateCommand(Action executeMethod, Func<bool> canExecuteMethod);        protected DelegateCommand(Func<Task> executeMethod);        protected DelegateCommand(Func<Task> executeMethod, Func<bool> canExecuteMethod);        //        // 摘要:        //     Factory method to create a new instance of Prism.Commands.DelegateCommand from        //     an awaitable handler method.        //        // 参数:        //   executeMethod:        //     Delegate to execute when Execute is called on the command.        //        // 返回结果:        //     Constructed instance of Prism.Commands.DelegateCommand        public static DelegateCommand FromAsyncHandler(Func<Task> executeMethod);        //        // 摘要:        //     Factory method to create a new instance of Prism.Commands.DelegateCommand from        //     an awaitable handler method.        //        // 参数:        //   executeMethod:        //     Delegate to execute when Execute is called on the command. This can be null to        //     just hook up a CanExecute delegate.        //        //   canExecuteMethod:        //     Delegate to execute when CanExecute is called on the command. This can be null.        //        // 返回结果:        //     Constructed instance of Prism.Commands.DelegateCommand        public static DelegateCommand FromAsyncHandler(Func<Task> executeMethod, Func<bool> canExecuteMethod);        //        // 摘要:        //     Determines if the command can be executed.        //        // 返回结果:        //     Returns true if the command can execute, otherwise returns false.        public virtual bool CanExecute();        //        // 摘要:        //     Executes the command.        public virtual Task Execute();        //        // 摘要:        //     Observes a property that is used to determine if this command can execute, and        //     if it implements INotifyPropertyChanged it will automatically call DelegateCommandBase.RaiseCanExecuteChanged        //     on property changed notifications.        //        // 参数:        //   canExecuteExpression:        //     The property expression. Example: ObservesCanExecute((o) => PropertyName).        //        // 返回结果:        //     The current instance of DelegateCommand        public DelegateCommand ObservesCanExecute(Expression<Func<object, bool>> canExecuteExpression);        //        // 摘要:        //     Observes a property that implements INotifyPropertyChanged, and automatically        //     calls DelegateCommandBase.RaiseCanExecuteChanged on property changed notifications.        //        // 参数:        //   propertyExpression:        //     The property expression. Example: ObservesProperty(() => PropertyName).        //        // 类型参数:        //   T:        //     The object type containing the property specified in the expression.        //        // 返回结果:        //     The current instance of DelegateCommand        public DelegateCommand ObservesProperty<T>(Expression<Func<T>> propertyExpression);    }}

第一次使用MVVM设计模式,没有理解在多个ViewModel之间通信,所以不得不采用单一ViewModel和多个view,这样导致了一个ViewModel的臃肿和复杂,看似结构简单,但是实际的逻辑越来越混乱。在没有理解Event Aggregator如何使用的情况下,这是可行方案。

MVVM使用感受

最主要的感受是MVVM将UI和业务逻辑分离,UI就只写UI,不用像WinForm一样在每个事件背后,如果要获得UI某个TextBox的数据,得通过如下获取

public void SomeButton_Clicked(object sender, EventArgs e){ string text = textBox1.Text;   DoSomeThings(text); ...}

同样,后台事件要更新前台UI数据时

pubic void SomeButton_Clicked(object sender, EvnetArgs e){   DoOtherThings();    textBox1.Text = "Some Text";}

这种硬编码的形式,遇到UI的重大变化,必须就将背后事件对应UI的控件名称全部更改才能继续运行。当软件达到一定复杂度,这样做就是灾难性的。

而MVVM,使用了数据绑定,虽然增加了一点代码,但是带来的好处巨大。在ViewModel中先定义要绑定的数据

private string name;public string Name{   get{return name;}   set{        if (name != value)     {           name = value;          OnPropertyChanged("Name"); // 实现INotifyPropertyChanged接口  }}}

然后在view中将其和TextBox数据绑定

<TextBox Text="{Binding Name, Mode=TwoWay}">

这里的数据绑定方式是双向绑定,后台数据变化会自动通知前台UI线程更新数据,相反,前台UI线程更改了数据,后台的数据也会相应变化。这样,在实际数据更新时,不用去查看绑定的UI控件名称,也不用担心在其他线程更新控件数据时要用oneControl.Invoke(Action action)

总结

第一次使用MVVM感受到的优点:

  • 数据绑定,不用考虑具体UI控件的名称,不用手动更新UI数据。

  • UI可操作性更大,支持template

  • 业务逻辑和UI分离,界面改版方便

但同样带来了缺点:

  • 代码量明显增加

  • 对于小软件来说,开发没有WinFrom来的敏捷

学习MVVM设计模式后第一次用于生产相关推荐

  1. MVC,MVP,MVVM设计模式的比较

    1. MVC设计模式 1.1 概述 意义 说明 M Model,表示模型层,数据模型或业务模型,就是我们要显示给用户查看的内容 V View,表示视图层,就是用户直接看到的界面,例如:Activity ...

  2. [译]WPF 应用程序和MVVM设计模式 ——Josh Smith

    这篇文章讨论: 模式与WPF MVP模式 为什么MVVM更加适用于WPF 用MVVM构建一个应用程序 译文地址:         http://www.cnblogs.com/lujiao_cs/ar ...

  3. 读取项目的根目录 部署tomcat后_tomcat配置根目录访问后,部署后第一次访问会出现tomcat的默认界面而非项目首页...

    tomcat配置根目录访问后,部署后第一次访问会出现tomcat的默认界面而非项目首页,而重启后会正常,这个原因是因为在配置文件中有如下配置,造成项目加载两次 unpackWARs="tru ...

  4. LLMs:《Building LLM applications for production构建用于生产的LLM应用程序》翻译与解读

    LLMs:<Building LLM applications for production构建用于生产的LLM应用程序>翻译与解读 LLMs:构建用于生产的LLM应用程序的挑战与案例经验 ...

  5. 翻译|R用于研究,Python用于生产

    **原文:**R is for Research, Python is for Production **作者:**Matt Dancho and Jarrell Chalmers, 2021-2-1 ...

  6. C语言学习一个月后感想

    C语言学习一个月后感想 感谢李晓东老板及计算机工程师联盟的学长学姐和某神秘同级同学的辛勤指导,感谢宋雨田的督促和陪伴. 初识C的1..体会 我本以为凭借瓜皮思维和花里胡哨操作可以让我熟练地学习语言,现 ...

  7. swift mvvm_Swift中的MVVM设计模式概述

    swift mvvm by Azhar 由Azhar Swift中的MVVM设计模式概述 (An overview of the MVVM design pattern in Swift) This ...

  8. 一台服务器创建多个ssh_如何创建可用于生产的第一台安全服务器

    一台服务器创建多个ssh by Flavio H. Freitas Flavio H.Freitas着 如何创建可用于生产的第一台安全服务器 (How to create your first saf ...

  9. 3ml乐谱制作工具_用于生产的ML基础结构工具(第1部分)

    3ml乐谱制作工具 重点 (Top highlight) Machine Learning (ML) is being adopted by businesses in almost every in ...

最新文章

  1. html 文字上下垂直居中
  2. sql server性能分析--执行sql次数和逻辑次数
  3. Design Pattern - Observer(C#)
  4. 给程序员的VIM速查卡
  5. quartz分布式集群部署并且可视化配置job定时任务
  6. 时间加减计算器_手机上的计算器这样也可以,太方便了,赶快转告家人朋友
  7. php 使用PDO,防止sql注入 简单说明
  8. android俄罗斯方块开发代码,基于Android的俄罗斯方块开发(附源码)
  9. Abp Quartz配置Sqlite
  10. 强行结束进程命令ntsd
  11. 【IIOT】欧姆龙PLC数采之NX/NJ系列
  12. 第一次部署海康威视DEMO的一些坑,最终运行成功
  13. 用英语详细介绍计算机系统的组成,第二节 计算机的基本组成及工作原理(国外英语资料).doc...
  14. 【AICG】动漫女主AI绘图的学习笔记
  15. 5000字长文:电商运营如何做好数据分析?
  16. atan函数和atan2函数的区别
  17. 【UWB 定位】高精度定位
  18. badger mremap size mismatch数据库异常
  19. 孙正义万字访谈:未来30年一切将被重新定义
  20. 高数:第五章(同济大学第七版)

热门文章

  1. android ota更新app,企业 OTA 更新  |  Android 开源项目  |  Android Open Source Project
  2. 火狐 增强查找工具栏_在“提示”框中:简单的IE至Firefox同步,轻松的Windows工具栏和识别USB电缆...
  3. 新手AS常见问题集锦
  4. Effective_STL 学习笔记(二十七) 用 distance 和 advance 把 const_iterator 转化成 iterator...
  5. 物联网离风口还差最关键一环?
  6. Nutch 是一个开源Java 实现的搜索引擎
  7. 放弃winform的窗体吧,改用html作界面,桌面应用程序UI的新的开发方式。
  8. 【组图】地震前线归来--心中的震撼
  9. C#10 和 .NET6 代码跨平台开发
  10. 微信发力了,一键部署网站后端!