我们都想追求完美


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 application would still compile and run correctly

Josh Smith说可以删除views' codebehind文件,程序也能正常运行。

stylet框架作者是这么说的“Stylet lets you delete the codebehind entirely (it will call InitializeComponent for you), and you are strongly encouraged to do so. Delete the codebehind!”

啊...还有这么完美的事情?那是不是views' codebehind文件里一行代码都不写,所有的代码都可以写在ViewModel里就可以了,那这样显示层和业务逻辑层就可以完美分离了?

理想是丰满的,现实却是骨干的啊!为了追求极致的MVVM,在实际项目开发中会把自己搞的非常纠结,不知从何下手...

比如使用的第三方控件,它不支持依赖项属性,那我们只能把代码写在views' codebehind文件里。问题来了,这个控件要使用ViewModel里的逻辑,那View怎么访问ViewModel的方法呢?ViewModel里要获取这个控件的数据,那ViewModel如何调用View里的方法呢?搜了一通,发现这个问题不好搞...

这个“老鼠屎”控件破坏了我们实现完美MVVM的计划,哎呀,这时候开始后悔使用MVVM了,后悔使用WPF了,干脆使用WinForm方式开发算了,或者找个第三方MVVM框架,看能不能解决...我当初就有这种心理。

下面通过一个简单的demo来演示,如何解决上面的两个问题:

View中使用ViewModel


我们在程序启动的时候已经使用了相应的ViewModel初始化了View的DataContext

/// <summary>
/// App.xaml 的交互逻辑
/// </summary>
public partial class App : Application
{
protected override void OnStartup(StartupEventArgs e)
{
base.OnStartup(e); var vw = new MainWindow();
var vm = new MainWindowViewModel();
vw.DataContext = vm;
vw.Show();
}
}

因此在View中,我们可以通过DataContext获取ViewModel

private MainWindowViewModel _vm;

private void OnLoaded(object sender, RoutedEventArgs e)
{
if (_vm == null)
{
_vm = this.DataContext as MainWindowViewModel;
...
}
}

在View中使用ViewModel中的属性或方法

private void LvPersons_OnSelectionChanged(object sender, SelectionChangedEventArgs e)
{
var item = this.LvPersons.SelectedItem as PersonModel;
if (item != null)
{
_vm.PersonProfile = string.Format("姓名:{0}, 性别:{1}, 年龄:{2};", item.Name, item.Sex, item.Age);
}
}

注:可以使用blend提供的System.Window.interactivity插件,将View中事件转换为ViewModel中命令

ViewModel中使用View


先定义一个接口

namespace MVVMSample.Comm
{
public interface IView
{
void SetAddress(Uri uri);
}
}

View中初始化并实现这个接口

public partial class MainWindow : IView
{
private void OnLoaded(object sender, RoutedEventArgs routedEventArgs)
{
if (_vm == null)
{
_vm = this.DataContext as MainWindowViewModel;
if (_vm != null)
{
_vm.View = this;
}
}
} ... public void SetAddress(Uri uri)
{
this.Wb.Navigate(uri);
}
}

ViewModel中定义并使用View中的接口

public IView View { private get; set; }

...

public ICommand NavigationCmd
{
get
{
if (_navigationCmd == null)
{
_navigationCmd = new DelegateCommand(() =>
{
if (View != null)
{
//IView中接口方法
View.SetAddress(new Uri("http://www.bing.com"));
}
});
}
return _navigationCmd;
}
}

问题总算解决了,关键是,使用上述方法还能够进行单元测试。

总结


跟业务逻辑相关的操作一定要放到ViewModel中,跟业务逻辑无关的可以放到Views' Codebehind文件里。MVVM模式是开发中的指导原则,不能强套,需要灵活使用。

WPF之MVVM模式(2)的更多相关文章

  1. 【WPF】MVVM模式的3种command

    原文:[WPF]MVVM模式的3种command 1.DelegateCommand 2.RelayCommand 3.AttachbehaviorCommand 因为MVVM模式适合于WPF和SL, ...

  2. WPF之MVVM模式讲解

    WPF技术的主要特点是数据驱动UI,所以在使用WPF技术开发的过程中是以数据为核心的,WPF提供了数据绑定机制,当数据发生变化时,WPF会自动发出通知去更新UI. 恰当的模式可以让我们轻松达到“高内聚 ...

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

    1.DelegateCommand 2.RelayCommand 3.AttachbehaviorCommand 因为MVVM模式适合于WPF和SL,所以这3种模式中也有一些小差异,比如RelayCo ...

  4. WPF之MVVM模式(1)

    MVVM模式 一.MVVM模式概述 MVVM Pattern : Model\View\ViewModel View:视图.UI界面 ViewModel:ViewModel是对Model的封装,通过一 ...

  5. WPF中MVVM模式的 Event 处理

    WPF的有些UI元素有Command属性可以直接实现绑定,如Button 但是很多Event的触发如何绑定到ViewModel中的Command呢? 答案就是使用EventTrigger可以实现. 继 ...

  6. WPF之MVVM模式(3)

    有种想写一个MVVM框架的冲动!!! 1.Model中的属性应不应该支持OnPropertyChanged事件? 不应该.应该有ViewModel对该属性进行封装,由ViewModel提供OnProp ...

  7. WPF中 MVVM模式的Slider Binding.

    对于Button的Command的绑定可以通过实现ICommand接口来进行,但是Slider并没有Command属性. 另外如果要实现MVVM模式的话,需要将一些Method和Slider的Even ...

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

    MVVM绑定 view-viewModel-model,模型介绍省略,就是创建类,添加字段封装属性.注:控件的绑定只能绑定到属性上,不能绑定到字段上: 接下来就是代码 (view): <Wind ...

  9. WPF中MVVM模式下控件自有的事件绑定

    1.原因 在WPF中单纯的命令绑定往往不能满足覆盖所有的事件,例如ComboBox的SelectionChanged事件,DataGrid的SelectionChanged事件等等,这时就可以用事件绑 ...

随机推荐

  1. shell split函数的使用

    #!/bin/awk -f BEGIN{FS=","} {split($1,name," "); for (i in name) print name[i] }

  2. bzoj 4503 两个串——FFT

    题目:https://www.lydsy.com/JudgeOnline/problem.php?id=4503 翻转T,就变成卷积.要想想怎么判断. 因为卷积是乘积求和,又想到相等的话相减为0,所以 ...

  3. 得到properties配置文件内容

    代码: 1.配置文件内容 2.文件所在项目中位置: 3.java代码: 01.得到键值对: @Test public void getProp() { Properties prop = new Pr ...

  4. MSDN 学习网站

    -MSDN中文网站http://msdn.microsoft.com/zh-cn/-MSDN Webcast 中文网络广播http://msdn.microsoft.com/zh-cn/dd79616 ...

  5. calc PI

    https://en.wikipedia.org/wiki/Pi code https://github.com/HHS-IntroProgramming/Calculate-Pi https://g ...

  6. ManualResetEvent 用法

    第一.简单介绍 ManualResetEvent 允许线程通过发信号互相通信.通常,此通信涉及一个线程在其他线程进行之前必须完成的任务.当一个线程开始一个活动(此活动必须完成后,其他线程才能开始)时, ...

  7. Python类(三)-多继承的区别

    多继承的有两个方式,一个是广度优先,一个是深度优先Python2中经典类按深度优先,新式类按广度优先Python3中经典类和新式类都按广度优先 # -*- coding:utf-8 -*- __aut ...

  8. CreateThread demo

    #include "stdafx.h"#include<windows.h>#include<strsafe.h>//win2003SDK必须安装 要不无此 ...

  9. CIA泄露资料分析(黑客工具&技术)—Windows篇

    背景 近期,维基解密曝光了一系列据称来自美国中央情报局(CIA)网络攻击活动的秘密文件,代号为“Vault 7”,被泄露文件的第一部分名为“Year Zero”,共有8761个文件,包含7818个网页 ...

  10. 删除CentOS系统自带的jdk

    转自:https://www.cnblogs.com/linjiqin/archive/2013/03/23/2977377.html 在安装CentOS6.4时,系统会自动安装jdk,先把它下载掉, ...