MVVM架构

MVVM是Model-View-ViewModel的简写。它本质上就是MVC 的改进版。MVVM 就是将其中的View 的状态和行为抽象化,让我们将视图 UI 和业务逻辑分开。当然这些事 ViewModel 已经帮我们做了,它可以取出 Model 的数据同时帮忙处理 View 中由于需要展示内容而涉及的业务逻辑。微软的WPF带来了新的技术体验,如Silverlight、音频、视频、3D、动画……,这导致了软件UI层更加细节化、可定制化。同时,在技术层面,WPF也带来了 诸如Binding、Dependency Property、Routed Events、Command、DataTemplate、ControlTemplate等新特性。MVVM(Model-View-ViewModel)框架的由来便是MVP(Model-View-Presenter)模式与WPF结合的应用方式时发展演变过来的一种新型架构框架。它立足于原有MVP框架并且把WPF的新特性糅合进去,以应对客户日益复杂的需求变化。

mvvm模式将Presener改名为View Model,基本上与MVP模式完全一致,唯一的区别是,它采用双向绑定(data-binding): View的变动,自动反映在View Model,反之亦然。这样开发者就不用处理接收事件和View更新的工作,框架已经帮你做好了

WPF双向数据同步:目标属性(UI)和源属性(CS)数据同步。

实现双向数据同步数据源需要实现依赖属性INotifyPropertyChanged接口,因为依赖属性有垂直的内嵌变更通知机制。

INotifyPropertyChanged是用于实现界面通知。
DependencyObject是实现依赖对象的依赖属性。

UI是一个XAML绑定数据

<TextBox Name="txtName" Text="{Binding user.Name}"></TextBox>
<TextBox Name="txtEmail" Text="{Binding user.Email}"></TextBox>
<Button Command="{Binding SendCommand}" Content="发送消息"  Margin="15,0,0,0"></Button>

Model层,实现INotifyPropertyChanged接口,属性的变化通过OnPropertyChanged通知到UI。

// 实现依赖属性INotifyPropertyChanged接口

using System;
using System.ComponentModel;
 
namespace WPFBinding
{
    /// <summary>
    /// 实现INotifyPropertyChanged接口
    /// </summary>
    public class Users : INotifyPropertyChanged
    {
        /// <summary>  
        /// 姓名  
        /// </summary>  
        private string _Name;
        public string Name
        {
            get
            {
                return _Name;
            }
            set
            {
                _Name = value;
                OnPropertyChanged("Name");
            }
        }
        /// <summary>  
        /// Email  
        /// </summary>  
        private string _Email;
        public string Email
        {
            get
            {
                return _Email;
            }
            set
            {
                _Email = value;
                OnPropertyChanged("Email");
            }
        }
        protected internal virtual void OnPropertyChanged(string propertyName)
        {
            PropertyChanged?.Invoke(this, new PropertyChangedEventArgs(propertyName));
        }
        public event PropertyChangedEventHandler PropertyChanged;
    }
}

那么问题来了,这个地方仅仅穿了一个字符串“Name”,怎么做到通知UI上TextBox变化的呢。其实这里用到了反射,去通知UI对象修改属性值。

查看源码,你会看到内部定义的一些反射调用来改变属性值,因此UI对象的属性也就变了。这个框架已经帮你做好,只需要传个字符串,就可以通知到你绑定的UI字段变化。

{
    this.InvokeInternal<DependencyObject>("NotifySubPropertyChange", new object[] { DpColorProperty });
}

/// <summary>
/// 反射调用指定类型的 Internal 方法。
/// </summary>
/// <typeparam name="T"></typeparam>
/// <param name="caller"></param>
/// <param name="method"></param>
/// <param name="parameters"></param>
/// <returns></returns>
public static object InvokeInternal<T>(this T caller, string method, object[] parameters)
{
	MethodInfo methodInfo = typeof(T).GetMethod(method, BindingFlags.Instance | BindingFlags.NonPublic);
	return methodInfo?.Invoke(caller, parameters);
}

ViewModel层

// ViewModel初始化
namespace WPFBinding
{
    public class ViewModel
    {
        public Users user { get; set; }
        public ViewModel()
        {
            this.user = new Users();
        }
    }
}

// 交互逻辑,实例化数据
using System;
using System.Windows;
 
namespace WPFBinding
{
    /// <summary>
    /// MainWindow.xaml
    /// </summary>
    public partial class MainWindow : Window
    {
        public ViewModel viewModel;
        public MainWindow()
        {
            InitializeComponent();
            this.viewModel = new ViewModel();
            this.Loaded += (s, e) =>
            {
                this.DataContext = viewModel;
                this.viewModel.user = new Users()
                {
                    Name = "张三",
                    Email = "123@email"
                };
            };
        }
    }
}