在上一章中,我们只是开了个头而已,然而在这一章中,我们将看到一点实际的代码了。我构想了很久,怎样让新手能快速掌握我想要传达的知识,然后我得出一个结论:一定一定要简单化,并且要有看的见摸的着的代码实例。好吧,我们开始。

打开你的VS2010,新建一个WPF项目,命名为MvvmTutorial即可。紧接着,在当前Solution添加4个文件夹,分别为:Infrastructure, Views, ViewModels, Models。然后,把App.xaml改成如下:

<Application x:Class="MvvmTutorial.App"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml" >
</Application >

把MainWindow.xaml,MainWindow.xaml.cs删掉。在Views下添加一个新的WPF Window,命名为ShellView。在App.xaml.cs中加入:

protected override void OnStartup(StartupEventArgs e)
{
base.OnStartup(e);
var shell = new ShellView();
shell.Show();
}

都完成了吗?现在按F5,你应该可以看到你的程序正常运行,并且已经可以看到主窗体了。至此,我们只是做了一些准备工作。Shell其实就是壳的意思,每一个Windows程序都会有一个主窗体,也就是一个壳,我们在这个壳上面拼凑各种View来构成一个丰富的应用程序。

现在我们来看一下具体我们要做些什么。我说过,尽量简单化,所以我们这章的任务很简单:就是把一些联系人显示在主窗体里。我们的联系人很简单,只有两个属性:名字和电话号码。我个人喜欢从ViewModel这一层出发,但是许多朋友还是习惯从Model层写起,那么我们就先来研究一下Model,即实体。在第一章中有人问是否应该在Model里实现INotifyPropertyChanged 接口 ,我个人认为这个没有特别的死的做法。有点人愿意把Model尽量简单化,也就是说只是一个数据的载体而已,而把所有与View打交道的事情全部推给ViewModel。然而对于我们这个简单的例子,我选择让Model也实现INotifyPropertyChanged接口,如此一来,当我们对Model做出修改后,View上就可以显示出变化了(不过在今天这一章里,我们暂时不讨论ViewModel/Model的修改)。现在,在Models下添加一个Contact类。

我们的Model,很简单,具体是这个样子的:

using MvvmTutorial.Infrastructure;

namespace MvvmTutorial.Models
{
/// <summary >
/// Our Contact model, which stores data retrieved from data persistence layer
/// </summary >
public class Contact : ObservableObject
{
#region Fields

string _name;
string _phoneNumber;

#endregion // Fields

#region Properties

public string Name
{
get
{
return _name;
}
set
{
if (_name != value)
{
_name = value;
RaisePropertyChanged(() = > Name);
}
}
}

public string PhoneNumber
{
get
{
return _phoneNumber;
}
set
{
if (_phoneNumber != value)
{
_phoneNumber = value;
RaisePropertyChanged(() = > PhoneNumber);
}
}
}

#endregion // Properties
}
}

你们可能注意到了这个Contact实际上继承了ObservableObject。这是一个抽象的基类,由于我们将来会有很多类都要实现INotifyPropertyChanged接口,所以我在这里写了一个基类。在Infrastructure下添加一个ObservableObject:

using System;
using System.ComponentModel;
using System.Linq.Expressions;

namespace MvvmTutorial.Infrastructure
{
public class ObservableObject : INotifyPropertyChanged
{
public event PropertyChangedEventHandler PropertyChanged;

public virtual void RaisePropertyChanged(string propertyName)
{
if (PropertyChanged != null)
{
PropertyChanged(this, new PropertyChangedEventArgs(propertyName));
}
}

public void RaisePropertyChanged<T >(Expression<Func<T > > propertyExpression)
{
var propertyName = PropertySupport.ExtractPropertyName(propertyExpression);
this.RaisePropertyChanged(propertyName);
}
}
}

好的,这里我要说一下,其实这个类不是我个人写的,而是“剽窃”了一些现有的开源代码,拼凑起来的。请注意PropertySupport,这是一个静态类,它其实来自于微软的Prism框架里一小段代码,我之所以这样做只是让大家看的更清楚这些MVVM的框架内部大体是怎么回事,其实都是大同小异的。请在Infrastructure下添加PropertySupport:

using System;
using System.Linq.Expressions;
using System.Reflection;

namespace MvvmTutorial.Infrastructure
{
public static class PropertySupport
{
public static string ExtractPropertyName<T >(Expression<Func<T > > propertyExpression)
{
if (propertyExpression == null)
{
throw new ArgumentNullException("propertyExpression");
}

var memberExpression = propertyExpression.Body as MemberExpression;
if (memberExpression == null)
{
throw new ArgumentException("The expression is not a member access expression.", "propertyExpression");
}

var property = memberExpression.Member as PropertyInfo;
if (property == null)
{
throw new ArgumentException("The member access expression does not access a property.", "propertyExpression");
}

var getMethod = property.GetGetMethod(true);
if (getMethod.IsStatic)
{
throw new ArgumentException("The referenced property is a static property.", "propertyExpression");
}

return memberExpression.Member.Name;
}
}
}

有的人可能会问“PropertySupport”到底是干嘛的?其实我们经常写这样的代码:RaisePropertyChanged("SomeProperty"),这个代码本身没有任何问题,但是我们传入的是一个string,这也就暗示了两个小问题:1.当你的Property改名字以后,你需要修改这个string;2.输入string是个稍微容易出错的过程(打字错误)。那么PropertySupport.ExtractPropertyName便在牺牲了一点点效率的前提下,通过指定一个Expression来获得其属性的名字。所以我们就可以写成:RaisePropertyChanged(() = > PhoneNumber);如此一来,你只需要指定哪个属性即可,至于它的名字,不需要你操心,而且当下次你修改PhoneNumber为PrivatePhoneNumber后,你也不需要修改任何string。

Okay,既然我们说了要显示出一系列联系人,我们便需要一个View和ViewModel。在ViewModels下添加ContactMasterViewModel:

using System.Collections.Generic;
using System.Collections.ObjectModel;
using MvvmTutorial.Infrastructure;
using MvvmTutorial.Models;

namespace MvvmTutorial.ViewModels
{
public class ContactMasterViewModel : ObservableObject
{
#region Fields

private bool _isLoaded;
private ObservableCollection<Contact > _items = new ObservableCollection<Contact >();

#endregion // Fields

#region Properties

public IEnumerable<Contact > Items
{
get
{
// If we load this view model in design mode (for example, in VS or Expression),
// we add some random data so that we can preview the layout of our view
if (DesignHelper.IsInDesignMode)
{
for (int i = 0; i < 25; ++i)
{
_items.Add(new Contact().GenerateRandomData());
}
}
else if (!_isLoaded)
{
Load();
}
return _items;
}
}

#endregion // Properties

#region Private Methods

private void Load()
{
// TODO: Once we finish the implementation of data persistence layer,
// we need to re-write this code to make this method work for real-world app.

// We haven't implemented data persistence
// Therefore, we temporarily load some random data in memory
for (int i = 0; i < 25; ++i)
{
_items.Add(new Contact().GenerateRandomData());
}
_isLoaded = true;
}

#endregion // Private Methods
}
}

注意这里面的DesignHelper:在Infrastructure下添加DesignHelper类:

MVVM教程(2):相关推荐

  1. MVVM教程[资源+分析]

    - Model-View-ViewModel是一种架构模式,主要在WPF.Silverlight和WP7开发里使用,它的目标是从视图层移除几乎所有代码隐藏(code-behind).交互设计师可以专注 ...

  2. java用mvvm,[Java教程]MVVM架构~使用boxy和knockoutjs实现编辑功能

    [Java教程]MVVM架构~使用boxy和knockoutjs实现编辑功能 0 2014-04-24 14:00:08 返回目录 这个功能我认为非常有用,尤其在后台管理系统中,它对用户来说,使用体验 ...

  3. 迷你MVVM框架 avalonjs 学习教程20、路由系统

    迷你MVVM框架 avalonjs 学习教程20.路由系统 时间 2014-10-28 14:44:00  Ruby's Louvre 原文  http://www.cnblogs.com/rubyl ...

  4. 迷你MVVM框架 avalonjs 入门教程

    api大全 OniUI组件库 学习教程 视频教程: 地址1 地址2 关于AvalonJs 开始的例子 扫描 视图模型 数据模型 绑定 作用域绑定(ms-controller, ms-important ...

  5. 迷你MVVM框架 avalonjs 入门教程(司徒正美)

    迷你MVVM框架 avalonjs 入门教程 关于AvalonJs 开始的例子 扫描 视图模型 数据模型 绑定属性与动态模板 作用域绑定(ms-controller, ms-important) 模板 ...

  6. WPF教程(十五)MVVM框架

    作者本人以前是做C++的,当然很顺利的进入到WinForm,这也让我基本没有View-Model思维.学习WPF说白点也是因为其强大的UI,其实我忽视了很重要的一点,直到接触了MVVM框架,其实Web ...

  7. WPF框架教程 | 从0到1:使用Caliburn.Micro(WPF和MVVM)开发简单的计算器

    之前时间一直在使用Caliburn.Micro这种应用了MVVM模式的WPF框架做开发,是时候总结一下了. Caliburn.Micro(https://blog.csdn.net/lzuacm/ar ...

  8. 我的MVVM框架 v3教程——todos例子

    每个MVC框架都爱搞个todos演示 它的HTML如下: <!--[if IE 6]><center style="display:inline-block;zoom:1; ...

  9. WPF初学者的福音,高效的MVVM数据绑定教程

    WPF原生搭建MVVM架构操作繁琐,代码冗杂,这里推荐使用CommunityToolkit_mvvm. 右键你的项目,选择管理Nuget程序包,选择包括预发行版,搜索communitytookit_m ...

最新文章

  1. powerbi输入数据_Power BI 的多种共享方式
  2. api可以主动采集用户数据吗_数据埋点采集的那些事儿
  3. Java数据结构和算法( 二 ) ## 数组
  4. 跨域请求,关于后端session会话丢失的解决办法
  5. 神策数据杨宁:财富管理转型趋势下的精细化运营
  6. 重试次数配置_TestNG实践——2.用例失败重试
  7. OpenCV添加(混合)两个图像
  8. 设计模式六大原则 图
  9. 模型预测控制 索引超出数组元素的数目(0)。_C++基础总结(二):C++基本数据类型及流控制语句详解...
  10. Win7系统账户被禁用的解决方法
  11. Qt工作笔记-Qt之自定义属性Q_PROPERTY
  12. Swift 语言概览 -自己在Xcode6 动手写1
  13. xml样本标签转txt
  14. Java中常用的设计模式
  15. 概率论基础知识整理(一)
  16. Elasticsearch.service failed after enable elasticsearch security features
  17. linux编译安卓源码,Ubuntu下编译Android源码
  18. vue 直接访问静态图片_在使用vue中实现本地静态图片路径(详细教程)
  19. 【Mesh】关于Mesh中Seq+IV与RPL分析
  20. 关于CodeBlocks下载了带mingw版本的依旧无法编译运行的解决方案

热门文章

  1. OpenJudge NOI 1.7 17:字符串判等
  2. 线性结构 —— 分块算法
  3. 相离的圆(51Nod-1278)
  4. 图论 —— 网络流 —— 最大流 —— Dinic 算法
  5. 训练日志 2019.2.14
  6. Problem Solving(POJ-3265)
  7. 仙岛求药(信息学奥赛一本通-T1251)
  8. 网络商务信息与计算机的关系,计算机与电子商务的关系,
  9. linux那些事之LRU(3)
  10. linux procfs文件系统(2)