我们都想追求完美


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. C#:使用UPnP来穿透NAT使内网接口对外网可见

    在写完Object 672后,软件的一个致命问题暴露出来,如果服务器和客户端都在内网环境下,即双方都通过NAT来接触外网,那么此时客户端是无法直接和服务器交流的. 解决方案可以是: 1:把服务器部署在 ...

  2. untra edit 显示文件函数列表

    UltraEdit的函数列表竟然不显示函数,那这功能要它何用,应该如何才能让函数显示出来呢? 1:先查看一下UE的菜单:视图-->查看方式(语法高亮类型)-->选择相应的语言(我们用的是C ...

  3. 开始写博客,与ITer们互相学习

    学习计算机也6年了,一直待在学校里.这些年来很多学习资料都来自网络上的技术博客,非常感谢各位 ITer 的分享精神,鄙人从中受益匪浅.从今天起也挤出时间开始写技术博客.主要是把自己这些年的一些技术文档 ...

  4. [转]A记录和CNAME记录的区别

    1.什么是域名解析? 域名解析就是国际域名或者国内域名以及中文域名等域名申请后做的到IP地址的转换过程.IP地址是网路上标识您站点的数字地址,为了简单好记,采用域名来代替ip地址标识站点地址.域名的解 ...

  5. 1、Monkey入门准备教程

    1.前提需要Android环境 ADT:链接: https://pan.baidu.com/s/1QN6EJh46cJGvUBaMZjtiWw 密码: a7zu Eclipse:https://www ...

  6. linux user date

    useradd username 添加用户 userdel username 删除用户 passwd username 设置用户密码 passwd 设置当前用户密码 passwd -d usernam ...

  7. java写出进程条代码

    package com.ds; import java.awt.Color; import java.awt.Toolkit; import javax.swing.ImageIcon; import ...

  8. js页面埋点

    页面埋点的作用,其实就是用于流量分析.而流量的意思,包含了很多:页面浏览数(PV).独立访问者数量(UV).IP.页面停留时间.页面操作时间.页面访问次数.按钮点击次数.文件下载次数等.而流量分析又有 ...

  9. PostgreSQL recovery.conf恢复配置

    PostgreSQL recovery.conf恢复配置 这一章描述recovery.conf 文件中可用的设置.它们只应用于恢复期.对于你希望执行的任意后续恢复, 它们必须被重置.一旦恢复已经开始, ...

  10. 2016.7.27 VS搜索正则表达式,在UltraEdit中可选用Perl正则引擎,按C#语法搜索

    表达式 语法 说明 任一字符 . 匹配除换行符外的任何一个字符. 最多 0 项或更多 * 匹配前面表达式的 0 个或更多搜索项. 最多一项或更多 + 匹配前面表达式的至少一个搜索项. 最少 0 项或更 ...