MVVM模式--Model,View,ViewModel三者平衡

来源:互联网 发布:算法c语言实现pdf 网盘 编辑:程序博客网 时间:2024/05/23 01:11

MVC的概念已经逐渐被大家所熟悉——Model,View,Controllor。但是在最近的开发过程中,特别与WPF相关的开发中,发现MVVM这个模式相当好用,而且还可以很方便的通过UnitTest了检查UI的错误。

    什么是MVVM呢,就是ModelViewViewModel

  • Model就是对数据的抽象,数据的封装。比如,Person。
  • View就是UI表现层,提供与终端用户的交互。比如,一个用户录用界面。
  • ViewModel是这种模式的核心,提供了一个Model与View之间的桥梁。它应该提供了View中所有用户可能的操作对应的处理,以及该处理能去Model进行必要的操作,或者缓存该处理结果,等待下次使用。

    让我们举的例子。

    Case 1:我们有一个Person的Model和一个选择Person的界面。那么,我们需要一个IsSelected的属性来标记用户的选择。但是把IsSelected属性放入Person类肯定是不合适的,而且可能你根本就没有权力可以修改Person类。所以我们建立一个PersonViewModel的类,里面有Person类的对象,并提供IsSelected属性。这样View就可以对PersonViewModel直接操作,如果是WPF的话,就可以直接绑定了。

    Case 2:让我们在Case1的基础上给View加一些功能,有一个Enroll的按钮,如果用户点击,那么被选中的Person就会被录用。那么这个时候,我们就需要在PersonViewModel里面再增加一个Enroll的方法,在该方法里去操作Person的Enrollment的一些信息。

    Case 3:我们还需要告诉View,被录用的Person的录用信息。那么我们在PersonViewModel中增加一个Enrollment的属性,当被Enroll的时候,通知Enrollment属性被改变了,View就能更新数据了。

 

     为什么用MVVM模式?

     一是为了把View层的逻辑抽象到了VIewModel中,又保持了Model的数据独立性。可以把ViewModel层当成逻辑的抽象,但是应该同时包括业务逻辑和页面逻辑。

     二是为了方便我们测试代码,以前对含有UI的测试,Unit Test是不够的,但是因为有了VIewModel这层,我们可以通过ViewModel来模拟用户的操作。

 

     这个模式的确是一个很适合WPF的开发的模式。

Example Code:

Person.cs


    public class Person

    {

        public string Name { get; set; }

        public string Company { get; set; }

        public string EnrolledBy { get; set; }

        public DateTime EnrollDate { get; set; }

    }

 

    public sealed class PersonViewModel : INotifyPropertyChanged

    {

        public Person MyPerson { get; set; }

 

        public PersonViewModel(Person person)

        {

            this.MyPerson = person;

        }

 

        private bool isSelected;

 

        public bool IsSelected

        {

            get { return isSelected; }

            set 

            {

                if (isSelected != value)

                {

                    isSelected = value;

                    PropertyChange("IsSelected");

                }

            }

        }

 

        public string Enrollment

        {

            get

            {

                if (string.IsNullOrWhiteSpace(MyPerson.Company))

                {

                    return string.Empty;

                }

                return string.Format("Company {0} enrolled this guy at {1}.", MyPerson.Company, MyPerson.EnrollDate); 

            }

 

        }

 

        public void Enroll(string companyName, string enrollBy)

        {

            MyPerson.Company = companyName;

            MyPerson.EnrolledBy = enrollBy;

            MyPerson.EnrollDate = DateTime.Now;

 

            PropertyChange("Enrollment");

        }

 

 

        private void PropertyChange(string propertyName)

        {

            if (PropertyChanged != null)

            {

                PropertyChanged(this, new PropertyChangedEventArgs(propertyName));

            }

        }

 

        public event PropertyChangedEventHandler PropertyChanged;

    }

 

MainWindow.xaml


<Window x:Class="WpfApplication1.MainWindow"

        xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"

        xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml" 

        x:Name="Main"

        Title="MainWindow" Height="350" Width="525">

    <Grid>

        <CheckBox Content="" Height="16" HorizontalAlignment="Left" Margin="42,33,0,0" Name="checkBox1" VerticalAlignment="Top" IsChecked="{Binding Path=Person.IsSelected, Mode=TwoWay, ElementName=Main}"/>

        <TextBlock Height="23" HorizontalAlignment="Left" Margin="79,33,0,0" Name="textBlock1" VerticalAlignment="Top" Width="210" Text="{Binding Path=Person.MyPerson.Name, ElementName=Main}" />

        <Button Content="Enroll" Height="23" HorizontalAlignment="Left" Margin="79,79,0,0" Name="button1" VerticalAlignment="Top" Width="75" Click="button1_Click" />

        <TextBlock Height="23" HorizontalAlignment="Left" Margin="306,33,0,0" Name="textBlock2" VerticalAlignment="Top" Width="146" Text="{Binding Path=Person.Enrollment, ElementName=Main}" />

    </Grid>

</Window>

 

MainWindow.xaml.cs

 

        public PersonViewModel Person

        {

            get { return (PersonViewModel)GetValue(PersonProperty); }

            set { SetValue(PersonProperty, value); }

        }

 

        // Using a DependencyProperty as the backing store for Person.  This enables animation, styling, binding, etc...

        public static readonly DependencyProperty PersonProperty =

            DependencyProperty.Register("Person", typeof(PersonViewModel), typeof(MainWindow));

 

 

 

        public MainWindow()

        {

            InitializeComponent();

 

            Person = new PersonViewModel(new Person() { Name = "John" });

 

        }

 

        private void button1_Click(object sender, RoutedEventArgs e)

        {

            Person.Enroll("Microsoft", "Microsoft HR");

        }

原创粉丝点击