Prism学习笔记(二)简单的MVVM模式

现在我们进入Prism的一条重要支柱MVVM模式。MVVM模式简单来说就是把页面UI和后台逻辑分开,这样做的好处是能使你的程序更容易测试,维护和改进。下面的图来自于Prism4的教程显示了MVVM模式的基本工作原理:

好,废话少说,开始Coding吧。

打开之前创建的MyPrism程序:

其中HelloWorldModule下只有一个View页面HelloWorldView.xaml,其只实现一个简单显示HelloWorld控件作用,不包括任何逻辑代码。

为了实现MVVM模式,我们需要添加一个ViewModel文件和Model文件。

在Helloworldmodule下新建两个文件夹,命名为Models和ViewModels,分别添加一个cs文件,如下图:

接下来,修改HellowWorldView页面,实现一个简单的加法界面

 代码如下:

<UserControl x:Class="HelloWorldModule.Views.HelloWorldView"
xmlns
="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x
="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:d
="http://schemas.microsoft.com/expression/blend/2008"
xmlns:mc
="http://schemas.openxmlformats.org/markup-compatibility/2006"
mc:Ignorable
="d"
xmlns:ds
="clr-namespace:HelloWorldModule.ViewModels"
d:DesignHeight
="429" d:DesignWidth="618" xmlns:sdk="http://schemas.microsoft.com/winfx/2006/xaml/presentation/sdk">

<UserControl.DataContext>
<ds:HelloWorldViewModel/>
</UserControl.DataContext>

<Grid x:Name="LayoutRoot" Background="White">
<Grid.RowDefinitions>
<RowDefinition Height="63"/>
<RowDefinition Height="40"/>
<RowDefinition Height="50"/>
</Grid.RowDefinitions>
<Grid.ColumnDefinitions>
<ColumnDefinition Width="150"/>
<ColumnDefinition Width="50"/>
<ColumnDefinition Width="150"/>
<ColumnDefinition Width="50"/>
<ColumnDefinition Width="150"/>
</Grid.ColumnDefinitions>

<TextBlock Grid.ColumnSpan="5" Text="Hello World" Foreground="Green" HorizontalAlignment="Center" VerticalAlignment="Center" FontFamily="Calibri" FontSize="24" FontWeight="Bold"></TextBlock>
<TextBox Grid.Row="1" Grid.Column="0" Height="23" Name="Number1" Text="{Binding HelloWorldModel.Number1, Mode=TwoWay}" Width="120"/>
<TextBox Grid.Row="1" Grid.Column="2" Height="23" Name="Number2" Text="{Binding HelloWorldModel.Number2, Mode=TwoWay}" Width="120"/>
<sdk:Label Grid.Row="1" Grid.Column="4" Height="28" Name="Result" Content="{Binding HelloWorldModel.Result, Mode=TwoWay}" Width="120"/>
<sdk:Label Grid.Row="1" Grid.Column="1" Height="23" Name="label1" Content="+" Width="30"/>
<sdk:Label Grid.Row="1" Grid.Column="3" Height="22" Name="label2" Content="=" Width="30"/>
<Button Content="Add" Grid.Row="2" Grid.Column="4" Command="{Binding AddCommand}" Height="25" Name="btnAdd" Width="75"/>

</Grid>
</UserControl>




其中的关键代码:

xmlns:ds="clr-namespace:HelloWorldModule.ViewModels"

<UserControl.DataContext>
<ds:HelloWorldViewModel/>
</UserControl.DataContext>


这里吧HellowWorldViewModel类所为HellowWorldView的DataContext,也就是说View中的所有数据绑定都在HellowWorldViewModel类中定义。

<TextBox Grid.Row="1" Grid.Column="0"  Height="23"  Name="Number1" Text="{Binding HelloWorldModel.Number1, Mode=TwoWay}" Width="120"/>
<TextBox Grid.Row="1" Grid.Column="2" Height="23" Name="Number2" Text="{Binding HelloWorldModel.Number2, Mode=TwoWay}" Width="120"/>
<sdk:Label Grid.Row="1" Grid.Column="4" Height="28" Name="Result" Content="{Binding HelloWorldModel.Result, Mode=TwoWay}" Width="120"/>

这三个控件中,Text绑定了HelloWorldModel.Number1属性,并且是双向绑定,双向绑定既是,如果程序既可以将HelloWorldModel.Number1属性绑定到页面,也可以从页面得到数据。如将其改为单向绑定,程序就无法读取客户输入的数字了。

 

<Button Content="Add" Grid.Row="2"  Grid.Column="4" Command="{Binding AddCommand}" Height="25"  Name="btnAdd" Width="75"/>

此处将Button绑定到我们自定义的AddCommand中。

好接下来我们就要在HellowWorldViewModel类中实现Number1,Number2,Result这个三个绑定参数和AddCommand命令。

下面是HellowWorldModel类代码

using System.ComponentModel;

namespace HelloWorldModule.Models
{
public class HelloWorldModel : INotifyPropertyChanged
{
public event PropertyChangedEventHandler PropertyChanged;

public int Number1 { get; set; }

public int Number2 { get; set; }

private int result;

public int Result
{
get
{
return this.result;
}

set
{
if (value != this.result)
{
this.result = value;
if (this.PropertyChanged != null)
{
this.PropertyChanged(this, new PropertyChangedEventArgs("Result"));
}
}
}
}

}
}


在HellowWorldModel类中我们定义了基本的参数属性Number1,Number2,Result。Number1,Number2较为简单。Result中包含了一个PropertyChanged的事件,该事件的作用简单来说就是,一旦Result值发生了变化,他将通知所有的绑定Result的控件,刷新数据。为了实现该事件,该类必须继承INotifyPropertyChanged。具体的原理这里就不多说了,网上多的是。

HellowWorldViewModel类代码

using System.Collections.Generic;
using System.Diagnostics;
using System.Text;
using System.Windows.Input;
using Microsoft.Practices.Prism.Commands;
using HelloWorldModule.Models;

namespace HelloWorldModule.ViewModels
{
public class HelloWorldViewModel
{
private readonly HelloWorldModel helloWorldModel;

public HelloWorldViewModel()
{
this.helloWorldModel = new HelloWorldModel();
this.AddCommand = new DelegateCommand<object>(this.OnSubmit);
}

public HelloWorldModel HelloWorldModel
{
get { return this.helloWorldModel; }
}

public ICommand AddCommand { get; private set; }

private void OnSubmit(object obj)
{
helloWorldModel.Result = helloWorldModel.Number1 + helloWorldModel.Number2;
}


}
}

HellowWorldViewModel中创建了一个HellowWorldModel的实例,同时创建AddCommand方法,并实现其具体操作OnSubmit,这些都用来绑定到HellowWorldView中。

OnSubmit中将Number1和Number2的数据相加赋给了Result,由于属性Result实现了PropertyChanged事件,其值一发生变化,便刷新了Result控件值。

好所有的代码都完成了,按F5键运行,得到以下结果。

这篇文章主要是谈了MVVM模式的基本架构和功能实现。关键就在于数据绑定和PropertyChanged事件。

另外读者可能会有疑惑为什么要把HellowWorldModel类和HellowWorldViewModel类分开写,其实完全可以把两者和为一个类。Prism官方给出的ViewModel和Model的区别是:

ViewModel:The view model in the MVVM pattern encapsulates the presentation logic and data for the view. Viewmodel封装了展现的逻辑和数据。

Model:The model in the MVVM pattern encapsulates business logic and data. Model封装了业务的逻辑和数据。

笔者里的理解是分开是为了使代码更清晰,便于阅读。像页面操作如本例中的数据相加操作属于页面的逻辑,因此放在HellowWorldViewModel中,如果有数据库读取或者和其他模块交互,那就属于业务逻辑,就应该放在HellowWorldModel中。

希望大家指正。

源代码:https://files.cnblogs.com/mindflying/MyPrism_BasicMVVM.zip

 

posted @ 2011-10-31 23:38  FlyingSheep  阅读(1393)  评论(5编辑  收藏  举报