WPF之MVVM模式(2)
我们都想追求完美
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)的更多相关文章
- 【WPF】MVVM模式的3种command
		原文:[WPF]MVVM模式的3种command 1.DelegateCommand 2.RelayCommand 3.AttachbehaviorCommand 因为MVVM模式适合于WPF和SL, ... 
- WPF之MVVM模式讲解
		WPF技术的主要特点是数据驱动UI,所以在使用WPF技术开发的过程中是以数据为核心的,WPF提供了数据绑定机制,当数据发生变化时,WPF会自动发出通知去更新UI. 恰当的模式可以让我们轻松达到“高内聚 ... 
- 【转】【WPF】MVVM模式的3种command
		1.DelegateCommand 2.RelayCommand 3.AttachbehaviorCommand 因为MVVM模式适合于WPF和SL,所以这3种模式中也有一些小差异,比如RelayCo ... 
- WPF之MVVM模式(1)
		MVVM模式 一.MVVM模式概述 MVVM Pattern : Model\View\ViewModel View:视图.UI界面 ViewModel:ViewModel是对Model的封装,通过一 ... 
- WPF中MVVM模式的 Event 处理
		WPF的有些UI元素有Command属性可以直接实现绑定,如Button 但是很多Event的触发如何绑定到ViewModel中的Command呢? 答案就是使用EventTrigger可以实现. 继 ... 
- WPF之MVVM模式(3)
		有种想写一个MVVM框架的冲动!!! 1.Model中的属性应不应该支持OnPropertyChanged事件? 不应该.应该有ViewModel对该属性进行封装,由ViewModel提供OnProp ... 
- WPF中 MVVM模式的Slider Binding.
		对于Button的Command的绑定可以通过实现ICommand接口来进行,但是Slider并没有Command属性. 另外如果要实现MVVM模式的话,需要将一些Method和Slider的Even ... 
- WPF采用MVVM模式(绑定:纯前台、命令:触发器绑定命令)
		MVVM绑定 view-viewModel-model,模型介绍省略,就是创建类,添加字段封装属性.注:控件的绑定只能绑定到属性上,不能绑定到字段上: 接下来就是代码 (view): <Wind ... 
- WPF中MVVM模式下控件自有的事件绑定
		1.原因 在WPF中单纯的命令绑定往往不能满足覆盖所有的事件,例如ComboBox的SelectionChanged事件,DataGrid的SelectionChanged事件等等,这时就可以用事件绑 ... 
随机推荐
- 终于解决了一个Win7 下 VS 编译的问题,困扰了我好几个月
			用 Win7 一年多了,一直在这个环境下编程,其他都挺好,就是有个问题非常恶心,在VS下编译经常出现进程正在使用,无法覆盖的错误,这个问题我记得博问中以前也有其他人遇到过,也没有解决掉.此问题困扰了我 ... 
- js性能优化文章集锦
			总结的js性能优化方面的小知识http://www.it165.net/pro/html/201503/35336.html 如何优化你的JS代码http://www.php100.com/html/ ... 
- (转)C#程序开发中经常遇到的10条实用的代码
			原文地址:http://www.cnblogs.com/JamesLi2015/p/3147986.html 1 读取操作系统和CLR的版本 OperatingSystem os = System.E ... 
- install 命令
			install命令的作用是安装或升级软件或备份数据,它的使用权限是所有用户.install命令和cp命令类似,都可以将文件/目录拷贝到指定的地点.但是,install允许你控制目标文件的属性.inst ... 
- kafka集群安装和kafka-manager
			1.软件环境 (3台服务器-测试)10.11.12.31 mykafka110.11.12.32 mykafka210.11.12.33 mykafka3 [root@localhost ~]# ca ... 
- __align(num) 分析
			这几天用2440读写SD卡(FAT32文件系统),定义了个文件信息的数据结构里边数据类型有unsigned char, unsigned int, unsigned long几种,在从SD卡上读取数据 ... 
- Windows Bypass UAC
			Windows 10 sdclt UAC bypass @echo off reg add "HKCU\Software\Microsoft\Windows\CurrentVersion\A ... 
- CentOS 7.2 部署Rsync + Lsyncd服务实现文件实时同步/备份 (二)
			发送端配置: 一.配置密钥 1. 主/从服务器之间启用基于密钥的身份验证.登录发送端服务器并用 " ssh-keygen " 命令生成公共或私有的密钥. 2. 使用 " ... 
- Solaris10安装配置LDAP(iPlanet Directory Server )
			Solaris10安装光盘自带了iPlanet Directory Server安装包,系统管理员可以利用iPlanet Directory Server在Solaris系统创建一个LDAP Serv ... 
- 如何使32位Linux支持4G以上内存
			问题 Linux无法支持超过4G的内存,笔者使用的Linux是CentOS 5,机器是DELL PE1950服务器. 原因: X86系统默认寻址能力的限制 解决办法: 安装具有PAE(物理 ... 
