我们都想追求完美


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. 【转】JVM可视化工具插件---Visual GC

    Visual GC是一个Java 内存使用分析与GC收集的可视化工具插件 <插件下载> 一:整个区域分为三部分:spaces.graphs.histogram 1 spaces区域:代表虚 ...

  2. laravel redis的使用

    学习源头: https://www.cnblogs.com/redirect/p/6185228.html

  3. Qt多选框

    1.获取并显示复选框文本内容 ui->label->setText(ui->comboBox->currentText());

  4. [转载]python的range()函数用法

    使用python的人都知道range()函数很方便,今天再用到他的时候发现了很多以前看到过但是忘记的细节.这里记录一下range(),复习下list的slide,最后分析一个好玩儿的冒泡程序. 这里记 ...

  5. bash的使用

    转自:http://blog.csdn.net/y2888886/article/details/50535033 在上篇博文的基础上做如下修改 注意一些常见命令中间就要加 “ ” ,否则很多命令无法 ...

  6. DCloud-MUI:HBuilder 安装

    ylbtech-DCloud-MUI:HBuilder 安装 1.返回顶部 1. 2. 3. 4. 2.返回顶部   3.返回顶部   4.返回顶部   5.返回顶部     6.返回顶部   7.返 ...

  7. [iOS]UIImageView增加圆角

    [iOS]UIImageView增加圆角 "如何给一个UIImageView增加圆角?有几种方法?各自区别?" 备注:本文参考自http://www.jianshu.com/p/d ...

  8. Rails、Nginx、Passenger、bundle之间的协作关系

    引自:http://www.zhihu.com/question/20062163 Bundle是Gem包的依赖管理工具,RubyGem本身有依赖管理为何还要Bundle呢?有时候两个gem虽然都依赖 ...

  9. 简单叙述一下MYSQL的优化

    一个面试题.每次没能完全答对.各位补充一下.或者发表自己的答案:cry: 现在大概列出如下:(忘各位补充)1.数据库的设计尽量把数据库设计的更小的占磁盘空间.1).尽可能使用更小的整数类型.(medi ...

  10. 11-19网页基础--第二部分CSS样式表基本概念

    CSS,全称(Cascading Style Sheets,层叠样式表),作用是美化HTML网页. 一.基本概念:是用于(增强)控制网页样式并允许将样式信息与网页内容分离的一种标记性语言. 你可能对C ...