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"
};
};
}
}
}