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

189 篇文章 11 订阅
订阅专栏
9 篇文章 0 订阅
订阅专栏

  各位朋友大家好,我是Payne,欢迎大家关注我的博客,我的博客地址是http://qinyuanpei.com。最近因为项目上的原因开始接触WPF,或许这样一个在现在来讲显得过时的东西,我猜大家不会有兴趣去了解,可是你不会明白对某些保守的项目来讲,安全性比先进性更为重要,所以当你发现银行这类机构还在使用各种“复古”的软件系统的时候,你应该相信这类东西的确有它们存在的意义。与此同时,你会更加深刻地明白一个道理:技术是否先进性和其流行程度本身并无直接联系。由此我们可以推论出:一项不流行的技术不一定是因为它本身技术不先进,或许仅仅是因为它无法满足商业化的需求而已。我这里的确是在说WPF,MVVM思想最早由WPF提出,然而其发扬光大却是因为前端领域近年来比较热的AngularJS和Vue.js,我们这里表达的一个观点是:很多你以为非常新潮的概念,或许仅仅是被人们重新赋予了新的名字,当你理清这一切的来龙去脉以后,你会发现这一切并没有什么不同。这符合我一贯的主张:去发现问题的实质、不要被框架束缚、通过共性来消除差异,所以在今天这篇文章里,我想说说WPF中MVVM模式下命令与委托的关系。

什么是MVVM?

  既然提及MVVM,那么我们就无可避免的需要知道什么是MVVM。我们在本文开篇已经提到,MVVM这个概念最早由微软提出,具体来讲是由微软架构师John Gossman提出的。我个人更喜欢通过将MVC、MVP和MVVM这三者横向对比的方式来加强理解,因为这从某种意义上来讲,这是一个逐步改进和演化的过程。我们常常谈及软件的三层架构,我们常常对MVC耳濡目染以致将其神化,可事实上它们是某种在思想上无限接近的理念而已。

MVC模式示意图

  首先,我们从最简单的MVC开始说起,作为最常用的软件架构之一,我们可以从上面的图示中看到,MVC其实是非常简单的一个概念,它由模型(Model)、视图(View)和控制器(Controller)三部分组成,建立在一个单向流动的通信基础上,即View通知Controller响应用户请求,Controller在接到View的通知后会更新Model内的数据,然后Model会将新的数据反馈给View。我们发现这个设计可以使软件工程中的关注点分离,我们注意到通过MVC模式,我们实现了视图和模型的分离,通过控制器这个胶水层让两者间接联系起来,所以MVC的优点是让各个模块更好的协作。那么,它的缺点是什么呢?显然,视图和控制器是高度耦合的,因为控制器中无可避免地要访问视图内的元素,所以控制器注定无法在这尘世间独善其身。要知道最早的MVC架构是基于观察者模式实现的,即当Model发生变化时会同时通知View和Controller,所以我们很快就可以认识到:我们从古至今的所有努力,都是为了让视图和模型彼此分离,我们在这条路上越走越远,幸运的是一直都不忘初心。

MVP模式示意图

  接下来,我们为了彻底地让视图和模型分离,我们发明了新的软件架构:MVP。虽然从感性的认识上来讲,它是将Controller改名为Presenter,然而从理性的认识上来讲,它在让视图和模型分离这件事情上做得更为决绝果断。通过图示我们可以发现,视图和模型不再发生直接联系,它们都通过Presenter相互联系,而且各个部分间的通信都变成了双向流动。我们可以很快意识到,现在全新的控制器即Presenter会变得越来越“重”,因为所有的逻辑都在这里,而视图会变得越来越“轻”,它不再需要主动去获取模型提供的数据,它将被动地接拥抱变化,因为现在在视图里基本上没有任何业务逻辑。现在我们可以预见,人类会在隔绝视图和模型这件事情上乘胜追击,人们会尝试让Controller/Presenter/ViewModel变得越来越臃肿,我想说的是,求它们在得知这一切真相时的心理阴影面积,我们试图让每一个模块各司其职、通力协作,结果脏活累活儿都交给了Controller/Presenter/ViewModel,我想说这件事情做的真是漂亮。

MVVM模式示意图

  历史总是如此的相似,人类在作死的道路上匍匐前进,继续发扬改名的优良传统,这一次是Presenter被改名为ViewModel,在命名这件事情上,我认为程序员都是有某种强迫症因素在里面的,所以当你发现一个事物以一个新的名字出现在你的视野中的时候,通常它会有两种不同的结局,第一,陈酒换新瓶,我们贩卖的不是酒是情怀;第二,看今天的你我怎样重复昨天的故事,我这张旧船票还能否登上你的客船。幸运的是,MVVM相对MVP的确发生了些许改变,一个重要的特性是双向绑定,View的变化将自动反映在ViewModel中,而显然ViewModel是一个为View打造的Model,它可以容纳更多的普通的Model,因此从某种意义上来说,ViewModel依然作为连接View和Model的桥梁而出现,它是对View的一种抽象,而抽象有两层含义,即数据(Property)和行为(Command),一旦你明白了这一点,ViewModel无非是一个特殊而普通的类而已,特殊是因为它需要实现INotifyPropertyChanged接口,普通是因为它继承了面向对象编程(OOP)的基本思想。

更像MVC的MVVM

  到现在为止,我们基本上理解了MVC、MVP和MVVM这三者间的联系和区别,可是这样真的就是最好的结果吗?我们首先来思考一个问题,即什么样的代码应该写在控制器里。比如我们在对项目进行分层的时候,到底应该让控制器负责哪些任务?我们可以让Controller处理单独的路由,同样可以让Controller参与视图逻辑,甚至我们在编写Model的时候,我们可以有两种不同的选择,第一,编写一个简单的数据聚合实体,具体逻辑都交给控制器来处理,我们将这种方式称为贫血模型;第二,编写一个持有行为的数据聚合实体,控制器在业务逻辑中调用这些方法,我们将这种方式称为充血模型。所以,在这里我们纠结的地方,其实是选择让控制器更“重”还是让模型更“重”,我曾经接触过1年左右的Android开发,我认为Android工程是一个相对符合MVC架构的设计,可是我们难免会发现,作为控制器的Activity中的代码非常臃肿,因为我们在这里需要和视图、模型关联起来,所以综合现有的这些软件架构思想,我们发现模型和视图相对来讲都是可以复用的,可是作为连接这两者的Controller/Presenter/ViewModel是非常臃肿而且难以复用的,所以我怀疑我们是否是在真正的使用MVVM。

  我不知道MVVM架构正确的使用方法是什么样的,因为这是我第一次接触到这样一个新的概念,就如同很多年前,我在学校图书馆里看到的一本讲Web开发的书中描写的那样:当我们不了解MVC的时候,我们理所当然地认为通过文件夹将项目划分为Model、View、Controller,这样好像就是MVC啦。可是事实真的是这样吗?以我目前公司项目的情况而已,我认为它更像是使用了双向绑定的MVC,因为你经常可以在ViewModel中看到,某个属性的Get访问器中各种被if-else折磨的“脏”代码,而在ViewModel中我基本上看不到Model的身影,并且因为使用了Binding的概念严重弱化了ViewModel作为类的基本属性,因此它没有构造函数、没有初始化,我们可以在Get访问器中看到各种硬编码,因为视图上的需求经常变动,所以当整个项目结束的时候,我本人是非常不愿意去看ViewModel这部分的代码的,因为项目上要求避免写Code-Behind代码,所以大量的事件被Command和UIEventToCommand代替,这样让ViewModel变得更“重”了。原本我们希望的是让这三者各司其职,结果现在脏活累活儿全部变成了ViewModel一个人的。虽然双向绑定可以避免去写大量赋值语句,可是我知道ViewModel内心深处会表示:宝宝心里苦。

  如果说WPF对技术圈最大的贡献,我认为这个贡献不在双向绑定,而是它真正意义上实现了设计和编程分离,我们必须承认设计和编程都是一项创造性活动,前者趋向感性,而后者趋向理想,在没有实现这两者分离的时候,程序员需要花费大量时间去还原设计师的设计,可是对程序员来讲,一段程序有没有界面设计在某些场合下是完全不重要的,在没有界面设计的情况下,我们可以通过单元测试来测试代码的可靠程度,相反地在有了界面设计以后我们反而不容易做到这一点,所以你问我WPF对技术圈最大的贡献是什么,我会回答它解放了程序员,可以让理性思维去做理性思维更适合的事情。我不太喜欢声明式编程,这里是指WPF中XAML这种继承自XML的标记语言,因为Visual Studio对XAML没有提供调试的支持,所以当你发现视图显示出现问题的时候,你很难分清楚是前台视图绑定出现错误还是后台ViewModel出现错误,只要你输入符合XML规范的内容程序都会编译通过而非引发异常,因为它是用反射所以性能问题广为人所诟病,其次ViewModel中通知前台属性发生变化时需要使用OnPropertyChanged,该方法需要传入一个字符串类型的值,通常是指属性的名称,可是如果你定义了一个字符串类型的属性,当你在这里传入这个属性的时候,因为它是字符串类型所以不会引发编译错误,可是我觉得这个东西还是比较坑。

委托与命令

  好了,现在我想说说WPF中的命令和委托,事实上在我计划写这篇文章前,我对这里无比好奇,可当我发现这东西的实质以后,我忽然觉得花费如此大的篇幅来讲解这样一个概念,这是不是会显得特别无聊。我们的项目上使用的是一个叫做MVVM light的框架,当然我们没有使用它的全部功能,公司的前辈们非常猥琐地从这个开源项目中挑了些源代码出来,这里我不想提及关于这个框架本身地相关细节,因为我认为理解问题的实质比学会一个框架更加重要。首先,WPF为每一个控件都提供了一个Command的依赖属性,因为任何实现了ICommand接口的类都可以通过绑定的方式和前台关联起来,我们这里对比下命令和路由事件的区别可以发现,路由事件必须写在Code-Behind代码中,而命令可以写在ViewModel里,所以直观上来讲命令更加自由灵活。下面我们以一个简单的例子来剖析这两者间的关系。

  我们知道使用Command需要实现ICommand接口,所以实现起来是相对容易的,我们这里继续沿用MVVM light中的RelayCommand这个名字:

public class RelayCommand : ICommand
{
    private readonly Action<object> m_execute;
    private readonly Predicate<object> m_canExecute;

    public RelayCommand(Action<object> execute)
    {
        this.m_execute = execute;
    }

    public RelayCommand(Action<object> execute, Predicate<object> canExecute)
    {
        this.m_execute = execute;
        this.m_canExecute = canExecute;
    }

    public bool CanExecute(object parameter)
    {
        if (m_canExecute == null)
            return true;

        return m_canExecute(parameter);
    }

    public event EventHandler CanExecuteChanged
    {
        add { CommandManager.RequerySuggested += value; }
        remove { CommandManager.RequerySuggested -= value; }
    }

    public void Execute(object parameter)
    {
        this.m_execute(parameter);
    }
}

我们可以看到这里有两个重要的方法,Execute和CanExecute,前者是一个void类型的方法,后者是一个bool类型的方法。当我们需要判断控件是否应该执行某一个过程的时候,CanExecute这个方法就可以帮助我们完成判断,而Execute方法显然是执行某一个过程的方法,可以注意到通过委托我们让调用者更加自由和灵活地传入一个方法,这是我喜欢这种设计的一个地方,因为我的一位同事就对普通的路由事件表示无法理解。

  这里需要说明的是CanExecuteChanged这个事件,这个和INotifyPropertyChanged接口中的PropertyChanged成员类似,是在当CanExecute发生变化的时候通知视图的,我对这里的理解是CanExecute本身就具备对某一个过程是否应该被执行的支持,可是遗憾的是在,在我参与的项目中,人们更喜欢声明大量的布尔类型变量来处理这里的相关逻辑,因此无论是对Property还是Command而言,在ViewModel里都是看起来非常丑陋的代码实现。

  好了,现在对我们而言,这是一个非常愉快的旅程,因为在完成对RelayCommand的定义以后,我们绑定命令和定义命令的过程是非常简单的。除此以外,WPF提供了一个RoutedCommand类,该类实现了ICommand接口,我怀疑MVVM light中的EventToCommand正是通过这种思路实现了路由事件到命令的转换,因为只有RoutedCommand具备访问UI事件的能力,这里我们仅仅提出问题,进一步的思考和验证我们可以留到以后去做。下面我们来看看如何声明和绑定命令:

public RelayCommand ClickCommand
{
    get
    {
        return new RelayCommand((arg)=>
        {
            MessageBox.Show("Click");
        });
    }
}

显然这个ClickCommand将作为一个属性出现在ViewModel中,我选择了一个我最喜欢用的方法,或许这样看起来非常低端。可是在调试界面的过程中,它要比断点调试更为直接和直观。当我们的ViewModel中出现这样的只读属性的时候,直接在Get访问器中定义它的返回值似乎是最直接有效的方案,可问题是Get访问器应该是非常“轻”的,因为大量业务逻辑的渗透,现在连这里都不能保留其纯粹性了吗?这让我表示非常郁闷啊。

<Window x:Class="WPFLearning.Window1"
        xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
        xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
        Title="Window" Height="300" Width="300">
    <Grid>
        <Button Content="Button" HorizontalAlignment="Center" 
            VerticalAlignment="Center" Command="{Binding ClickCommand }"/>  
    </Grid>
</Window>

现在你可以发现,委托和命令结合得非常好,当你发现这一切如此美妙的时候,回归本质或许是我们最喜欢的事情,就像纯粹的你我一样,在这个世界上,我们彼此装点着各自生命里美好的风景,执著而勇敢、温暖而明媚,那些周而复始的日子里,总能听到梦想开花的声音。

小结

  在这篇文章里我们讨论了MVC、MVP、MVVM各自架构变迁的前因后果,由此我们知道了软件设计中,一个典型的设计目标是让视图和模型分离,可我们同样发现,带着这个目标去设计软件的时候,我们基本鲜有更换视图的时候,虽然从理论上来讲,所有的业务逻辑都是在ViewModel中,视图和模型应该是可以进行更换的,可是你告诉我,有谁会为同一个软件制作不同的界面呢?难道我们还能期望通过一个静态工厂,来为不同的平台返回不同的视图,然后理论上只要适配正确的控制器就可以实现软件对不同平台的“自适应”,可是软件开发领域发展至今,最有可能提供完整跨平台方案的Web技术目前都无法满足这个需求,所以我们是否应该去怀疑这个设计的正确性呢?同样的,以Java的SSH三大框架为代表的“配置文件”流派,认为应该将数据库的相关信息写在配置文件里,这样可以满足我们随时切换到不同数据库产品上的需要,可是你告诉我,这样的应用场景多吗?所以,技术本身的设计并没有问题,我们需要思考的是,是否应该被框架和架构束缚,说到底我们是为了设计出更棒的软件产品,以此为目标,其实框架和架构更应该衍生为一种哲学意义上的思想,我们想让每一行代码都充满智慧的光芒,它骄傲却不孤独,因为总有人理解它、懂它。

WPFMVVM模式,通过委托两个页面间通信
chendandan的博客
03-14 3299
需求:MVVM模式,在MainWindow的ViewModel接收到UserCOntrolB的Command事件
WPFMVVM模式详解(一)
最新发布
cunllp的专栏
02-20 321
详细讲解了WPF类的MVVM框架项目的建立过程。适合新手小白。
WPF MVVM简单介绍和使用
qq_39427511的博客
02-21 2710
MVVM是Model-View-ViewModel的简写,分为视图(View)、视图模型(ViewModel)、模型(Model)三部分。MVVM 模式就是将其的View 的状态和行为抽象化,形成数据绑定和命令,将视图 UI 和业务逻辑分开。由ViewModel处理相关的业务逻辑,与View对应,负责获取和更新Model的数据。
C# WPF MVVM模式Prism框架下事件发布与订阅
dotNET跨平台
11-20 812
01—前言 处理同模块不同窗体之间的通信和不同模块之间不同窗体的通信,Prism提供了一种事件机制,可以在应用程序低耦合的模块之间进行通信,该机制基于事件聚合器服务,允许发布者和订...
WPF MVVM系统入门-下
博客
02-16 1352
本文详细讲解WPFMVVM开发,实现UI与逻辑的解耦。
MVVM调用委托怎么不刷新
weixin_44545643的博客
06-01 175
MVVM项目里一般新增、修改、删除等操作需要刷新一般都会用委托命令来刷新页面,但是我遇到了一个问题,就是它新增跟删除都可以刷新页面,唯独修改刷新不了页面,我全都是调用委托命令来刷新页面的。在修改页面里面写好保存的方法,在修改成功之后调用委托刷新页面,如下: 先在修改页面里声明一个全局的委托 再在方法里面调用委托 然后再主页面里面利用委托调用页面加载的方法从而达到了刷新的效果。图下是主页面的写法 但是这里调用了委托也没用,断点看方法进去了但是查询出来的数据却是没有修改之前的数据,数据库的数据也改了。就
WPFMVVM模式下的命令绑定示例
02-23
WPFMVVM模式下的命令绑定示例,包括普通的Command绑定,和CommandParameter参数传入,还有其他命令通过System.Windows.Interactivity.WPF实现绑定和参数传入
WPFMVVM模式完整示例(登录窗口)
05-16
这个Demo是WPFMVVM模式的一个登录窗口的完整实例,包含了在MVVM模式下的数据绑定、命令和事件、PasswordBox的绑定、RadioButton等一对多控件的绑定、关闭窗口和打开新窗口和数据验证等内容。
wpfMVVM模式下窗体跳转及显隐控制实现
09-04
MVVM的,如何通过命令实现窗体之间的跳转、拖动以及显隐控制一直是困扰初学者的一个难题,本程序通过简单的示例代码,实现了这些功能,可以帮助初学者快速掌握这些基础操作。
浅析jsmvvm模式实现的原理
12-10
以Vue.js框架为例子,使用的mvvm模式 view指的是页面的html和css构成的视图。 model指的是从后端取到的数据模型 viewmodel 指的是前端开发人员组织生成和维护的视图数据层。这一层包含的是视图行为和数据。 视图...
WPF教程:MVVM模式的理解与应用
03-03
MVVM是Model-View-ViewModel的简写。...MVVM(Model-View-ViewModel)框架的由来便是MVP(Model-View-Presenter)模式WPF结合的应用方式时发展演变过来的一种新型架构框架。它立足于原有MVP框架并且把WPF的新特性
[WPF]MVVM Demo
12-07
Demo本身没有什么功能,只是包括一些UI上的逻辑,意在展示MVVM的开发方式和MVVMDemo.SysFramwork.MVVM下核心代码。
C# WPF 通过委托实现多窗口间的传值的方法
08-27
主要介绍了C# WPF 通过委托实现多窗口间的传值的方法,小编觉得挺不错的,现在分享给大家,也给大家做个参考。一起跟随小编过来看看吧
通过一个WPF实例进一步理解委托和事件
热门推荐
一蓑烟雨任平生 也无风雨也无晴
08-26 1万+
在前写过“浅谈C#委托”和“浅谈C#的事件”两篇博客,内容有些抽象,似乎难以说明委托和事件的关系。 今天通过一个小程序来进一步说明二者的使用及联系。 首先新建一个WPF应用程序,取名TestDelegateAndEvent。 在.xmal加入四个按钮,并添加Window_Loaded事件。 代码如下:<Window x:Class="TestDelegateAndEvent.Main
WPF MVVM Command的简单使用
dxm809的博客
03-07 719
1 新建wpf应用 2 新建Views,Models,ViewModels文件夹 3 新建Base文件夹,并在其里面新建CommandBase类 using System; using System.Collections.Generic; using System.Linq; using System.Text; using System.Threading.Tasks; using System.Windows.Input; namespace WpfApp1.Base { publi
MVVM - 委托和事件
IT_abmin的博客
05-08 197
MVVM - 委托 C#委托(Delegate): 简介:委托从字面上理解就是一种代理,类似于房屋介,由租房人委托介为其租赁房屋。在C#语言委托委托某个方法来实现具体的功能。委托是一种引用类型,虽然在定义委托时与方法有些相似,但不能将其称为方法。委托在使用时遵循三步走的原则,即定义声明委托、实例化委托以及调用委托。从数据结构来讲,委托是和类一样是一种用户自定义类型。委托是方法的抽象,它存储的就是一系列具有相同签名和返回回类型的方法的地址。调用委托的时候,委托包含的所有方法将被执行。委托是 C# 语
wpfmvvm模式实例
06-26
### 回答1: WPF(Windows Presentation Foundation)是一个基于XAML的应用程序框架,主要面向Windows桌面应用程序的开发。MVVM(Model-View-ViewModel)是一种设计模式,它将应用程序分为三个主要的部分:模型,视图和视图模型。在MVVM,视图和视图模型是分离的,视图模型呈现数据,并且视图与模型直接通信。 在WPFMVVM是一个广泛使用的模式,并且在实际应用程序实现起来非常简单。以下是一个MVVM模式实例: 我们建立一个学生管理系统,包括添加学生,编辑学生和显示学生。 首先是数据模型(Model),在这个例子,我们需要一个Student类,包括姓名,年龄和成绩。 ``` public class Student { public string Name { get; set; } public int Age { get; set; } public float Score { get; set; } } ``` 然后是视图模型(ViewModel),在这里我们需要三个属性:Students(学生列表),SelectedStudent(所选学生),和AddCommand(添加学生命令)。 ``` public class StudentViewModel : INotifyPropertyChanged { private ObservableCollection<Student> _students; private Student _selectedStudent; public ICommand AddCommand { get; private set; } public event PropertyChangedEventHandler PropertyChanged; public ObservableCollection<Student> Students { get { return _students; } set { if (_students != value) { _students = value; OnPropertyChanged("Students"); } } } public Student SelectedStudent { get { return _selectedStudent; } set { if (_selectedStudent != value) { _selectedStudent = value; OnPropertyChanged("SelectedStudent"); } } } public StudentViewModel() { Students = new ObservableCollection<Student>(); AddCommand = new RelayCommand(AddStudent); } private void AddStudent() { Students.Add(new Student() { Name = "New Student" }); } private void OnPropertyChanged(string propertyName) { if (PropertyChanged != null) { PropertyChanged(this, new PropertyChangedEventArgs(propertyName)); } } } ``` 最后是视图(View),在这个例子,我们需要一个包含学生列表和Add按钮的窗口。 ``` <Window x:Class="StudentManager.View.MainWindow" xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation" xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml" Title="Student Manager" Height="350" Width="525" DataContext="{StaticResource StudentViewModel}"> <Grid> <Grid.RowDefinitions> <RowDefinition Height="*" /> <RowDefinition Height="Auto" /> </Grid.RowDefinitions> <ListView ItemsSource="{Binding Students}" SelectedItem="{Binding SelectedStudent}"> <ListView.ItemTemplate> <DataTemplate> <StackPanel Orientation="Horizontal"> <TextBlock Text="{Binding Name}" Margin="5" /> <TextBlock Text="{Binding Age}" Margin="5" /> <TextBlock Text="{Binding Score}" Margin="5" /> </StackPanel> </DataTemplate> </ListView.ItemTemplate> </ListView> <Button Content="Add" Command="{Binding AddCommand}" Grid.Row="1" HorizontalAlignment="Right" Margin="5" Padding="5" /> </Grid> </Window> ``` 在这个例子,我们使用Data Binding(数据绑定)将视图与视图模型联系起来。数据绑定是指在WPF应用,允许将数据源与某个控件的属性绑定,当数据源更新时,UI自动更新。为了实现Data Binding,我们使用了INotifyPropertyChanged和RelayCommand。 INotifyPropertyChanged是一个接口,它使ViewModel可以通知视图它的属性已经更新。 RelayCommand是一个实现了ICommand接口的类,它将一些指定的命令关联到一个按钮,当条件满足时该按钮可以被按下。 在这个例子,我们建立了一个具有添加,编辑和显示学生信息的学生管理器。这个例子演示了MVVM模式如何在WPF实现,希望能帮助你更好的理解如何使用MVVM模式来构建应用程序。 ### 回答2: MVVM(Model-View-ViewModel)是一种软件设计模式,用于将GUI应用程序的UI与其后端逻辑分开。WPF(Windows Presentation Foundation)是一个微软框架,用于创建Windows桌面应用程序。 在WPF使用MVVM模式需要创建三种对象:模型(Model)、视图(View)和视图模型(ViewModel)。模型代表业务逻辑和数据,视图是用户界面,而视图模型则是连接两者的桥梁。 模型存储着应用程序的数据,我们需要编写类来表示数据结构。视图是XAML文件,包含了UI设计。视图模型是一个C#类,作为一种观察者模式,观察模型的变化并通知视图来更新。 在视图模型,需要维护着与视图交互的所有数据和命令。我们使用绑定(Binding)来处理两种对象之间的数据交互,从而实现视图和视图模型的解耦。 所以,实现WPFMVVM模式需要我们设计好模型、视图和视图模型之间的交互方式,很好的分离了应用程序的UI逻辑和后端业务逻辑,提高了应用程序的可维护性、可扩展性和可重用性。

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
写文章

热门文章

  • 在Unity3D中加载外部图片的两种方法 48816
  • Unity3D游戏开发之反编译AssetBundle提取游戏资源 48175
  • Unity3D游戏开发之游戏读/存档功能在Unity3D中的实现 47841
  • 使用C#开发HTTP服务器系列之Hello World 47786
  • Unity3D游戏开发之SQLite让数据库开发更简单 44786

分类专栏

  • 分布式丛林探险系列 付费 5篇
  • 海边的 Kafka 系列 付费
  • Unity3D 游戏开发系列 付费 88篇
  • Python 数据挖掘系列 付费 22篇
  • .NET 源代码探案系列 付费 29篇
  • Redis技术学习系列 4篇
  • C#设计模式系列 6篇
  • SDL游戏开发专栏 2篇
  • [编程之美] 10篇
  • [人生感悟] 26篇
  • [算法相关] 24篇
  • [编程语言] 189篇
  • [移动互联] 51篇
  • [游戏开发] 80篇
  • [产品设计] 9篇
  • [读书摘录] 12篇
  • [独立博客] 13篇
  • [SDLGame] 2篇
  • [NodeJS] 2篇

最新评论

  • 在Unity3D中使用uGUI实现3D旋转特效

    云来雁去: 本来就是伪 3D 啊,真 3D 我哪会做啊

  • 在Unity3D中使用uGUI实现3D旋转特效

    Gacy: 17年还在回复

  • 使用ASP.NET Core和Hangfire实现HTTP异步化方案

    aspnetSky: 有源码么

  • C# 使用 LibUsbDotNet 实现 USB 设备检测

    云来雁去: 自己定义一个类即可,当时忘记放上来了,抱歉表情包

  • C# 使用 LibUsbDotNet 实现 USB 设备检测

    Thinking_monkey: var args = new DeviceNotifierEventArgs(); 这里的DeviceNotifierEventArgs找不到命名空间?是需要引用别的库吗?

您愿意向朋友推荐“博客详情页”吗?

  • 强烈不推荐
  • 不推荐
  • 一般般
  • 推荐
  • 强烈推荐
提交

最新文章

  • 使用 EFCore 和 PostgreSQL 实现向量存储及检索
  • 基于 LLaMA 和 LangChain 实践本地 AI 知识库
  • 使用 llama.cpp 在本地部署 AI 大模型的一次尝试
2024年3篇
2023年7篇
2022年22篇
2021年36篇
2020年18篇
2019年19篇
2018年26篇
2017年16篇
2016年22篇
2015年44篇
2014年80篇
2013年35篇
2012年4篇

目录

目录

评论 6
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43元 前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

云来雁去

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或 充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值

深圳SEO优化公司泸州seo排名报价平湖外贸网站制作多少钱晋城百度网站优化排名哪家好十堰网站推广工具多少钱南澳网站优化排名多少钱长治百度标王多少钱鞍山网络广告推广哪家好曲靖百度竞价推荐河源营销型网站建设哪家好肇庆seo网站优化报价淮北百度标王报价大连SEO按效果付费公司海东网站设计报价爱联seo优化多少钱丹竹头网站改版报价益阳关键词按天收费多少钱天津SEO按天扣费价格沧州百度竞价哪家好玉林网站设计模板公司西安如何制作网站衡阳百度关键词包年推广价格晋城阿里店铺托管哪家好遵义网站关键词优化价格怀化百度竞价包年推广哪家好鞍山网站改版公司同乐SEO按效果付费报价湛江建站公司黑河网页制作张家口关键词排名多少钱怒江建设网站哪家好歼20紧急升空逼退外机英媒称团队夜以继日筹划王妃复出草木蔓发 春山在望成都发生巨响 当地回应60岁老人炒菠菜未焯水致肾病恶化男子涉嫌走私被判11年却一天牢没坐劳斯莱斯右转逼停直行车网传落水者说“没让你救”系谣言广东通报13岁男孩性侵女童不予立案贵州小伙回应在美国卖三蹦子火了淀粉肠小王子日销售额涨超10倍有个姐真把千机伞做出来了近3万元金手镯仅含足金十克呼北高速交通事故已致14人死亡杨洋拄拐现身医院国产伟哥去年销售近13亿男子给前妻转账 现任妻子起诉要回新基金只募集到26元还是员工自购男孩疑遭霸凌 家长讨说法被踢出群充个话费竟沦为间接洗钱工具新的一天从800个哈欠开始单亲妈妈陷入热恋 14岁儿子报警#春分立蛋大挑战#中国投资客涌入日本东京买房两大学生合买彩票中奖一人不认账新加坡主帅:唯一目标击败中国队月嫂回应掌掴婴儿是在赶虫子19岁小伙救下5人后溺亡 多方发声清明节放假3天调休1天张家界的山上“长”满了韩国人?开封王婆为何火了主播靠辱骂母亲走红被批捕封号代拍被何赛飞拿着魔杖追着打阿根廷将发行1万与2万面值的纸币库克现身上海为江西彩礼“减负”的“试婚人”因自嘲式简历走红的教授更新简介殡仪馆花卉高于市场价3倍还重复用网友称在豆瓣酱里吃出老鼠头315晚会后胖东来又人满为患了网友建议重庆地铁不准乘客携带菜筐特朗普谈“凯特王妃P图照”罗斯否认插足凯特王妃婚姻青海通报栏杆断裂小学生跌落住进ICU恒大被罚41.75亿到底怎么缴湖南一县政协主席疑涉刑案被控制茶百道就改标签日期致歉王树国3次鞠躬告别西交大师生张立群任西安交通大学校长杨倩无缘巴黎奥运

深圳SEO优化公司 XML地图 TXT地图 虚拟主机 SEO 网站制作 网站优化