技术笔记:WindowsPhoneMango:MVVM十分钟入门

简介: 技术笔记:WindowsPhoneMango:MVVM十分钟入门

在这篇文章中,我将谈一下在windows phone 7.1 Mango应用程序中使用MVVM设计模式。用较少的理论、更多的示例,在10分钟内来解释MVVM模式。


在开始之前,先简短介绍一下什么是MVVM:Model-View-ViewModel (MVVM)模式提供了一种灵活的方式,通过将应用程序分隔成三部分来创建windows phone应用程序。


a:View:放置XAML文件。


b:ViewModel:放置连接UI和数据的显示逻辑层。


c:放置数据模型和业务对象。


有关更多信息,看参阅官方MSDN文档。


为什么选择MVVM?有什么好处?


视图和显示逻辑层分离:从显示逻辑层分离出来View/XAML,可以使开发者只关注Code,而设计人员只关注XAML。


自动单元测试:视图/逻辑分离大大改进了表现逻辑层的自动单元测试。


代码重用:因为显示逻辑层在独立的组件或类中,和View(XAML)分离开来,你可以按照你喜欢的方式,通过继承和组合使它们结合起来。


设计时数据支持: 你可以在Blend中看到UI的样子,也就是说,设计人员可以使用样本数据来测试UI,甚至可以模拟实际场景数据。


多视图: 依据用户角色,同一ViewModel可以在不同的多视图中展现。


入门开始:


我们需要Windows Phone 7.1 Mango工程项目。在这个实例中,我们会使用上篇文章 为Windows Phone Mango MVVM 应用创建可复用 ICommand 实现类 所创建的DelegateCommand。请注意:commanding是伴随mango更新的新特性。(commanding意味着一些控件不支持Commands)。


MODEL


首先我们需要定义Model。在示例中,我们创建Person类,有两个属性:Name和Age。在这里,最重要的就是要实现INotifyPropertyChanged接口,因为,当Person对象发现变化时,需要通知给UI。(本例中,当按下Save Changes时,更新ListBox,更多信息参阅下面部分中的View)


using System;


using System.Net;


using System.Windows;


using System.Windows.Controls;


using System.Windows.Documents;


using System.Windows.Ink;


using System.Windows.Input;


using System.Windows.Media;


using System.Windows.Media.Animation;


using System.Windows.Shapes;


using System.ComponentModel;


namespace WPMangoMVVMSample


{


public class Person : INotifyPropertyChanged


{


private string name;


private int age;


public string Name


{


get


{


return name;


}


set


{


if (this.name != value)


{


this.name = value;


this.RaisePropertyChanged("Name");


}


}


}


public int Age


{


get


{


return this.age;


}


set


{


if (this.age != value)


{


this.age = value;


this.RaisePropertyChanged("Age");


}


}


}


public event PropertyChangedEventHandler PropertyChanged;


private void RaisePropertyChanged(string propertyName)


{


PropertyChangedEventHandler handler = this.PropertyChanged;


if (handler != null)


{


handler(this, new PropertyChangedEventArgs(propertyName));


}


}


}


}


.csharpcode, .csharpcode pre { font-size: small; color: rgba(0, 0, 0, 1); font-family: consolas, "Courier New", courier, monospace; background-color: rgba(255, 255, 255, 1) }


.csharpcode pre { margin: 0 }


.csharpcode .rem { color: rgba(0, 128, 0, 1) }


.csharpcode .kwrd { color: rgba(0, 0, 255, 1) }


.csharpcode .str { color: rgba(0, 96, 128, 1) }


.csharpcode .op { color: rgba(0, 0, 192, 1) }


.csharpcode .preproc { color: rgba(204, 102, 51, 1) }


.csharpcode .asp { background-color: rgba(255, 255, 0, 1) }


.csharpcode .html { color: rgba(128, 0, 0, 1) }


.csharpcode .attr { color: rgba(255, 0, 0, 1) }


.csharpcode .alt { background-color: rgba(244, 244, 244, 1); width: 100%; margin: 0 }


.csharpcode .lnum { color: rgba(96, 96, 96, 1) }


VIEW MODEL


下一步就是创建PersonViewModel,主要包含以下部分:


SaveChangesCommand - 保存用户选择Person对象所引发的修改。


LoadDataCommand - 此命令是用来填充ObservableCollection(Person对象)。


SelectedName - 此属性表示选中的Person对象的名称。


SelectedAge - 此属性表示选中的Person对象的年龄。


SelectedPerson - 此属性表示所选中的Person对象。


PersonViewModel也实现了INotifyPropertyChanged,所有当某些属性更新时,UI会接到通知。 代码如下:


using System;


using System.Net;


using System.Windows;


using System.Windows.Controls;


using System.Windows.Documents;


using System.Windows.Ink;


using System.Windows.Input;


using System.Windows.Media;


using System.Windows.Media.Animation;


using System.Windows.Shapes;


using System.ComponentModel;


using System.Collections.ObjectModel;


namespace WPMangoMVVMSample


{


public class PersonViewModel : INotifyPropertyChanged


{


private string name;


private int age;


private ObservableCollection


personDataSource;


private ICommand loadDataCommand;


private ICommand saveChangesCommand;


public PersonViewModel()


{


this.loadDataCommand = new DelegateCommand(this.LoadDataAction);


this.saveChangesCommand = new DelegateCommand(this.SaveChangesAction);


}


private void LoadDataAction(object p)


{


this.DataSource.Add(new Person() { Name = "John", Age = 32 });


this.DataSource.Add(new Person() { Name = "Kate", Age = 27 });


this.DataSource.Add(new Person() { Name = "Sam", Age = 30 });


}


private void SaveChangesAction(object p)


{


if (this.SelectedPerson != null)


{


this.SelectedPerson.Name = this.name;


this.SelectedPerson.Age = this.age;


}


}


public ICommand LoadDataCommand


{


get


{


return this.loadDataCommand;


}


}


public ICommand SaveChangesCommand


{


get


{


return this.saveChangesCommand;


}


}


public ObservableCollection


DataSource


{


get


{


if (this.personDataSource == null)


{


this.personDataSource = new ObservableCollection


();


}


return this.personDataSource;


}


}


public string SelectedName


{


get


//代码效果参考:http://www.lyjsj.net.cn/wx/art_23076.html

{

if (this.SelectedPerson != null)


{


return this.SelectedPerson.Name;


}


return string.Empty;


}


set


{


this.name = value;


}


}


public int SelectedAge


{


get


{


if (this.SelectedPerson != null)


{


return this.SelectedPerson.Age;


}


return 0;


}


set


{


this.age = value;


}


}


private Person selectedPerson;


public Person SelectedPerson


{


get


{


return this.selectedPerson;


}


set


{


if (this.selectedPerson != //代码效果参考:http://www.lyjsj.net.cn/wx/art_23074.html

value)

{


this.selectedPerson = value;


if (this.selectedPerson != null)


{


this.name = this.selectedPerson.Name;


this.age = this.selectedPerson.Age;


}


this.RaisePropertyChanged("SelectedName");


this.RaisePropertyChanged("SelectedAge");


}


}


}


public event PropertyChangedEventHandler PropertyChanged;


private void RaisePropertyChanged(string propertyName)


{


PropertyChangedEventHandler handler = this.PropertyChanged;


if (handler != null)


{


handler(this, new PropertyChangedEventArgs(propertyName));


}


}


}


}


.csharpcode, .csharpcode pre { font-size: small; color: rgba(0, 0, 0, 1); font-family: consolas, "Courier New", courier, monospace; background-color: rgba(255, 255, 255, 1) }


//代码效果参考: http://www.lyjsj.net.cn/wz/art_23072.html

.csharpcode pre { margin: 0 }


.csharpcode .rem { color: rgba(0, 128, 0, 1) }


.csharpcode .kwrd { color: rgba(0, 0, 255, 1) }


.csharpcode .str { color: rgba(0, 96, 128, 1) }


.csharpcode .op { color: rgba(0, 0, 192, 1) }


.csharpcode .preproc { color: rgba(204, 102, 51, 1) }


.csharpcode .asp { background-color: rgba(255, 255, 0, 1) }


.csharpcode .html { color: rgba(128, 0, 0, 1) }


.csharpcode .attr { color: rgba(255, 0, 0, 1) }


.csharpcode .alt { background-color: rgba(244, 244, 244, 1); width: 100%; margin: 0 }


.csharpcode .lnum { color: rgba(96, 96, 96, 1) }


VIEW


最后一步就是创建View。 我们仍然使用 MainPage.xaml。我们将创建:


"LoadData" 按钮: 调用LoadDataCommand填充数据源。


ListBox 绑定PersonViewModel,两个TextBox用来编辑选择的Person对象: 姓名和年龄。


"Save Changes" 调用SaveChangesCommand保存修改信息。


注意: TextBox的Binding 数据流向:Mode=TwoWay ,可以编辑和更新值。


[/span>StackPanel x:Name="ContentPanel" Grid.Row="1" Margin="12,0,12,0"

[/span>Button Content="LoadData" Command="{Binding LoadDataCommand}" />


[/span>ListBox ItemsSource="{Binding DataSource}" SelectedItem="{Binding SelectedPerson, Mode=TwoWay}" Height</span>="100"

[/span>ListBox.ItemTemplate

[/span>DataTemplate

[/span>StackPanel Orientation="Horizontal"

[/span>TextBlock Text="Name:"/>


[/span>TextBlock Text="{Binding Name}" />


[/span>TextBlock Text="Age:" Margin="10,0,0,0"/>


[/span>TextBlock Text="{Binding Age}" />






[/span>TextBlock Text="Name:"/>


[/span>TextBox Text="{Binding SelectedName, Mode=TwoWay}" />


[/span>TextBlock Text="Age:"/>


[/span>TextBox Text="{Binding SelectedAge, Mode=TwoWay}" />


[/span>Button Content="Save Changes" Command="{Binding SaveChangesCommand}" />



.csharpcode, .csharpcode pre { font-size: small; color: rgba(0, 0, 0, 1); font-family: consolas, "Courier New", courier, monospace; background-color: rgba(255, 255, 255, 1) }


.csharpcode pre { margin: 0 }


.csharpcode .rem { color: rgba(0, 128, 0, 1) }


.csharpcode .kwrd { color: rgba(0, 0, 255, 1) }


.csharpcode .str { color: rgba(0, 96, 128, 1) }


.csharpcode .op { color: rgba(0, 0, 192, 1) }


.csharpcode .preproc { color: rgba(204, 102, 51, 1) }


.csharpcode .asp { background-color: rgba(255, 255, 0, 1) }


.csharpcode .html { color: rgba(128, 0, 0, 1) }


.csharpcode .attr { color: rgba(255, 0, 0, 1) }


.csharpcode .alt { background-color: rgba(244, 244, 244, 1); width: 100%; margin: 0 }


.csharpcode .lnum { color: rgba(96, 96, 96, 1) }


绑定view至view model简单方法就是设置DataContext:


public MainPage()


{


InitializeComponent();


// simple way to bind the view to the view model


this.DataContext = new PersonViewModel();


}


.csharpcode, .csharpcode pre { font-size: small; color: rgba(0, 0, 0, 1); font-family: consolas, "Courier New", courier, monospace; background-color: rgba(255, 255, 255, 1) }


.csharpcode pre { margin: 0 }


.csharpcode .rem { color: rgba(0, 128, 0, 1) }


.csharpcode .kwrd { color: rgba(0, 0, 255, 1) }


.csharpcode .str { color: rgba(0, 96, 128, 1) }


.csharpcode .op { color: rgba(0, 0, 192, 1) }


.csharpcode .preproc { color: rgba(204, 102, 51, 1) }


.csharpcode .asp { background-color: rgba(255, 255, 0, 1) }


.csharpcode .html { color: rgba(128, 0, 0, 1) }


.csharpcode .attr { color: rgba(255, 0, 0, 1) }


.csharpcode .alt { background-color: rgba(244, 244, 244, 1); width: 100%; margin: 0 }


.csharpcode .lnum { color: rgba(96, 96, 96, 1) }


效果图:


源代码下载


译自:windowsphonegeek


由于本人翻译水平有限,有些地方欠妥,请园友们不吝指教!

相关文章
|
12月前
|
移动开发 程序员 编译器
三分钟创建一个新应用,ivx的神奇之处【PPT式程序开发】
IVX是一门人人都能快速掌握的可视化编程语言
93 0
|
前端开发
前端学习笔记202307学习笔记第六十天-Reconciler架构1
前端学习笔记202307学习笔记第六十天-Reconciler架构1
47 0
前端学习笔记202307学习笔记第六十天-Reconciler架构1
|
前端开发
前端学习笔记202307学习笔记第六十天-Reconciler架构2
前端学习笔记202307学习笔记第六十天-Reconciler架构2
47 0
|
5月前
|
编解码 数据可视化 小程序
微信小游戏开发(第一篇
微信小游戏开发(第一篇
222 0
|
12月前
|
设计模式 前端开发 JavaScript
前端Web开发学习,入门到进阶,推荐几本很不错的书籍
前端Web开发学习,入门到进阶,推荐几本很不错的书籍
138 0
|
前端开发
前端学习笔记202307学习笔记第六十天-Reconciler架构7
前端学习笔记202307学习笔记第六十天-Reconciler架构7
61 0
|
前端开发
前端学习笔记202307学习笔记第六十天-Reconciler架构8
前端学习笔记202307学习笔记第六十天-Reconciler架构8
54 0
|
前端开发
前端学习笔记202307学习笔记第六十天-搭建项目架构4
前端学习笔记202307学习笔记第六十天-搭建项目架构4
58 0
|
前端开发
前端学习笔记202307学习笔记第六十天-搭建项目架构2
前端学习笔记202307学习笔记第六十天-搭建项目架构2
62 0
|
前端开发
前端学习笔记202307学习笔记第六十天-搭建项目架构5
前端学习笔记202307学习笔记第六十天-搭建项目架构5
63 0
下一篇
无影云桌面