mvvm是silverlight/wpf下的mvc升华
通过一个简单的加法计算器例子来说明mvvm是什么
在设计界面完成设计之后,显示简单的布局,如下图:
然后来比较,传统的直接方式,mvc和mvvm三种的区别
1.最直接的方式无非就是双击Button按钮,在OnClick事件中获得两个TextBox的值,进行相加然后赋值给TextBlock
这样使得xaml.cs文件中直接操作了界面元素
2.mvc模式
首先定义一个AddModel类,并继承DependencyObject
public class AddModel:DependencyObject { public int Number1 { get { return (int)GetValue(Number1Property); } set { SetValue(Number1Property, value); } } // Using a DependencyProperty as the backing store for Number1. This enables animation, styling, binding, etc... public static readonly DependencyProperty Number1Property = DependencyProperty.Register("Number1", typeof(int), typeof(AddModel),null); public int Number2 { get { return (int)GetValue(Number2Property); } set { SetValue(Number2Property, value); } } // Using a DependencyProperty as the backing store for Number2. This enables animation, styling, binding, etc... public static readonly DependencyProperty Number2Property = DependencyProperty.Register("Number2", typeof(int), typeof(AddModel), null); public int Result { get { return (int)GetValue(ResultProperty); } set { SetValue(ResultProperty, value); } } // Using a DependencyProperty as the backing store for Result. This enables animation, styling, binding, etc... public static readonly DependencyProperty ResultProperty = DependencyProperty.Register("Result", typeof(int), typeof(AddModel), null); }继承了DependencyObject之后定义属性快捷方式如下:
定义好三个属性之后
在前台xaml文件引入命名空间
xmlns:my="clr-namespace:PhoneApp1"
<phone:PhoneApplicationPage.Resources> <my:AddModel x:Key="addModel"></my:AddModel> </phone:PhoneApplicationPage.Resources>
并将各个控件的Text属性绑定对应的值,模式为双向绑定
<Grid x:Name="ContentPanel" Grid.Row="1" DataContext="{StaticResource addModel}"> <TextBox x:Name="txtNumber1" Text="{Binding Number1,Mode=TwoWay}" VerticalAlignment="Top" Width="129"/> <TextBox x:Name="txtNumber2" Text="{Binding Number2,Mode=TwoWay}" VerticalAlignment="Top" Width="129"/> <TextBlock Text="+" VerticalAlignment="Top" RenderTransformOrigin="2.571,0.593"/> <Button Content="=" Click="Button_Click"/> <TextBlock x:Name="txtResult" Text="{Binding Result,Mode=TwoWay}" /> </Grid>
在xaml.cs后台中,使用Button的OnClick事件
private void Button_Click(object sender, RoutedEventArgs e) { AddModel addModel = (AddModel) Resources["addModel"]; addModel.Result = addModel.Number1 + addModel.Number2; }
并计算Result
启动运行
这样一来,在后台的xaml.cs中就没有操作界面元素了
但是还是要根据Button的OnClick事件才能实现
而在本例中mvvm模式的终极目标就是要消除OnClick!
3.mvvm模式
预备知识
Button有一个Command和CommandParameter属性
当Button的OnClick事件被触发时
Command属性对应的 继承了ICommand接口的类的Execute方法将会被执行,方法的参数是CommandParameter属性(Object类型)
于是需要一个新的类,叫做AddCommand,继承了ICommand接口
public class AddCommand:ICommand { public bool CanExecute(object parameter) { return true; } public void Execute(object parameter) { throw new NotImplementedException(); } public event EventHandler CanExecuteChanged; }
public ICommand AddCmd { get { return new AddCommand();} }返回xaml前台
在Button的属性中增加Command和CommandParameter属性的绑定
<Button Command="{Binding AddCmd}" CommandParameter="{Binding}" Content="=" HorizontalAlignment="Left" Margin="380,28,0,0" VerticalAlignment="Top"/>
启动运行
完成计算
这是后台中没有任何对前台界面元素的操作
mvvm完成
最后,思路有点乱
mvvm是靠一个继承了ICommand接口的类来实现的
当Button的OnClick事件被触发之后
Command属性对应的对象(这里为AddModel的AddCmd属性,该属性是只读的,返回一个AddCommand对象)的Execute方法会被执行
CommandParameter属性对应的值会被当做参数传入Execute方法(这里CommandParameter的值为AddModel本身)
在Execute方法中实现计算的操作
由于界面的控件数据源是双向绑定的
addModel的值一改变
界面就会显示出对应的值
那么这么做的好处是什么?
可以从代码中看到
前台的UI控件只要设置了数据源,并绑定了相应的属性就不需要进行任何操作了
在后台没有任务的业务逻辑处理的代码
所有的业务代码都在AddCommand的Execute方法中完成
而AddModel为UI控件的数据绑定提供了模型