首页 > 代码库 > 从头开始:详解MVVM、MVVMLight

从头开始:详解MVVM、MVVMLight

  • 究竟为什么要学习MVVM?

 

+ View Code?
相信大部分同学在刚开始接触MVVM的时候(包括我自己),心里默默在想这究竟是什么玩意?一个简单的功能要写一大段代码才能完成,在看到MVVM的核心目标:
 
1.让UI界面与逻辑能够很好地分离又协同工作。
 
2.让逻辑代码更具有可测试性。
 
会觉得我不把我的UI和逻辑分离,我的代码一样可以很好的分离又协同工作;
 
会觉得我不用MVVM我的代码一样测得好好的;
 
在这里,我先不说什么。我觉得这个需要自己意会了才能判断出自己的观点是正确的还是错误的。
  • 开始学习MVVM之前:
?
1
2
3
1.在开始学习MVVM你应该具备基本的C#(WPF或者SliverLight)的变成知识。如果你现在对这些还不熟悉,不建议先看这个,毕竟凡事都需要一步一步来。
 
2.本文主要拿WPF程序作为例子。例子源代码提供下载。
  • 学习绑定(Binding)

1.新建一个WPF项目

2.新建一个类:Model,Model代码如下:

    class Model
    {
        private string _text;

        public string Text
        {
            get { return _text; }
            set { _text = value; }
        }

        public Model()
        {
            _text = "HelloWorld";
        }
    }
Model代码

3.在MainWindows中放一个TextBox:

<TextBlock Text="{Binding Text}"/>
View Code

     TextBox的Text并没有显示制定值,而是绑定在一个名为"Text"的变量上面。但是目前这个程序还无法运行,因为编译器不知道“Text”这个变量是什么东西,所以需要给编译器指明这个“Text”在哪里。

     我们的目的是要把TextBox的Text属性绑定在Model类的Text属性上面,设置数据上下文(DataContext)就可以让编译器找到“Text”这个变量。

<Window x:Class="学习绑定.MainWindow"
        xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
        xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
        xmlns:local="clr-namespace:学习绑定"
        Title="MainWindow" Height="350" Width="525">
    <Window.DataContext>
        <local:Model/>
    </Window.DataContext>
    <Grid>
        <TextBlock Text="{Binding Text}"/>
    </Grid>
</Window>
View Code

现在程序应该可以运行了,效果如下:

刚开始学可以简单粗暴一点,绑定就是把一个值绑定在另一个值上面。绑定也是一个比较复杂的东西,这里不细讲,需要了解的朋友可以自己搜索下,太多的资料的。

在你觉得自己了解绑定之后就可以往下看了。

  •  开始第一个MVVM程序

 这个程序很简单,在界面中放置一个文本框和一个按钮很简单。文本框初始化的值为0.在点击按钮后,文本框的值加1.

界面XAML如下:

<Window x:Class="第一个MVVM程序.MainWindow"
        xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
        xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
        Title="MainWindow" Height="350" Width="525">
    <StackPanel>
        <TextBlock x:Name="Tb1"/>
        <Button Click="Button_Click" Content="点击我加1" Margin="0,10,0,0" HorizontalAlignment="Left"/>
    </StackPanel>
</Window>
View Code

 在没有了解MVVM之前,我们实现这个的过程很可能是这样:

public partial class MainWindow : Window
    {
        private int Num;

        public MainWindow()
        {
            InitializeComponent();
            Num = 0;
            Tb1.Text = Num.ToString();
        }

        private void Button_Click(object sender, RoutedEventArgs e)
        {
            Num++;
            Tb1.Text = Num.ToString();
        }
    }
View Code

实现后运行的效果如下:

 

根据上面学的绑定的知识,我们通过绑定的方式实现这个功能。

1.建立一个类Model

    class Model
    {
        private int _num;

        public int Num
        {
            get { return _num; }
            set { _num = value; }
        }

        public Model()
        {
            _num = 0;
        }
    }
View Code

 2.将文本框的Text属性绑定在Model的Text上面。(记住声明DataContext)

绑定之后,程序的Xaml代码就变成这样了: 

<Window x:Class="第一个MVVM程序.MainWindow"
        xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
        xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
        xmlns:local="clr-namespace:第一个MVVM程序"
        Title="MainWindow" Height="350" Width="525">
    <Window.DataContext>
        <local:Model/>
    </Window.DataContext>
    <StackPanel>
        <TextBlock x:Name="Tb1" Text="{Binding Num}"/>
        <Button Click="Button_Click" Content="点击我加1" Margin="0,10,0,0" HorizontalAlignment="Left"/>
    </StackPanel>
</Window>
View Code

 3.然后相应按钮的响应事件:

public partial class MainWindow : Window
    {
        private Model model;

        public MainWindow()
        {
            InitializeComponent();
            /*Xaml里面通过这样的方式为窗体添加了一个数据上下文
             * <Window.DataContext>
             *     <local:Model/>
             * </Window.DataContext>
             * 现在由于文本框的值绑定在Model的Text上面了,所有需要获取这个Model才能改变Text的值,
             * 改变了Text的值才能改变文本框显示的值
             */ 
            model = this.DataContext as Model;
        }

        private void Button_Click(object sender, RoutedEventArgs e)
        {
            model.Num++;
        }
    }
View Code

4.编译通过,开始运行。点击按钮后........妈蛋怎么文本框的值没有变?其实原因很简单。

我们先理清楚我们到目前为止在这个程序里面做了什么。

首先,我们建立了一个Model类,并在类里面写了一个属性"Text";

然后,我们将TextBlock的Text属性绑定在了Model的“Text”属性上面;

最后,我们发现在更改了Model的Text值后,TextBlock的值并没有发生变化。

可以确定的是,Model类的Text值肯定变化了。既然Model类的Text发生了变化,绑定也绑了,那么TextBlock的值怎么不变化?

实际上是因为你没有通知界面Text的值变了,所以界面就不知道实际上Model里面的Text已经发生变化,自然就没有必要更新界面了。

了解了问题产生的原因后,我们需要在Text发生变化后通知界面.为此,类Model需要实现"INotifyPropertyChanged"借口。从字面上就可以发现这个接口的意思就是“通知属性变化”。

实现后,Model类就变成这样了:

    class Model:INotifyPropertyChanged
    {
        private int _num;

        public int Num
        {
            get { return _num; }
            set 
            { 
                if(_num != value)
                {
                    _num = value;
                    NotifyPropertyChanged("Num");
                }
            }
        }

        public Model()
        {
            _num = 0;
        }

        public event PropertyChangedEventHandler PropertyChanged;

        private void NotifyPropertyChanged(string name)
        {
            if(PropertyChanged != null)
            {
                PropertyChanged(this, new PropertyChangedEventArgs(name));
            }
        }
    }
View Code

运行后,效果如下:

对于初学者,很难一下理解透这些过程和原理。其实你需要记住:但凡你想要在你的数据源发生变化,目标的值跟着发生变化,你都需要在数据源发生变化的时候通知目标。

未完待续。