啥是MVVM?

我理解的MVVM是Model(数据),View(界面),ViewModel(数据与界面之间的桥梁)的缩写,是一种编程模式。前期需要多花一些时间去编辑绑定,在后期维护方便。只需要关注数据即可。如:传统的界面更新需要去刷新界面才能读取到最新数据,在MVVM模式下只需要关注数据的更改,在该模式下可以实现控制界面自动更新。

一.数据是如何绑定到界面的?一步一步来!

  • 1.创建一个WPF项目,如在VS2022下创建WPF应用程序。(其他版本类似)

  • 2.项目创建好后,这里先创建Model数据类型。新建一个Model文件夹,添加一个ClassModel类,在此类中我们就写3个字段。

  • 3.新建View文件夹,添加一个MainView.xaml界面。再把启动界面改成MainView.xaml,这时候可以把项目自动生成的MainWindow.xaml删除掉了。

  • 4.布局MainView界面。

<Page x:Class="WPFMVVM.View.MainView"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
xmlns:local="clr-namespace:WPFMVVM.View"
mc:Ignorable="d"
d:DesignHeight="450" d:DesignWidth="500"
Title="MainView" Background="AliceBlue" FontFamily="行楷"> <Grid>
<Grid.RowDefinitions>
<RowDefinition />
<RowDefinition />
<RowDefinition />
<RowDefinition />
</Grid.RowDefinitions>
<Grid.ColumnDefinitions>
<ColumnDefinition />
<ColumnDefinition />
</Grid.ColumnDefinitions> <TextBlock
Grid.Row="0"
Grid.Column="0"
HorizontalAlignment="Right"
VerticalAlignment="Center"
FontSize="50"
Text="姓名:" /> <TextBlock
Grid.Row="0"
Grid.Column="1"
HorizontalAlignment="Left"
VerticalAlignment="Center"
FontSize="50"
Foreground="#0078d4"
Text="雅男" /> <TextBlock
Grid.Row="1"
Grid.Column="0"
HorizontalAlignment="Right"
VerticalAlignment="Center"
FontSize="50"
Text="年龄:" /> <TextBlock
Grid.Row="1"
Grid.Column="1"
HorizontalAlignment="Left"
VerticalAlignment="Center"
FontSize="50"
Foreground="#0078d4"
Text="20" />
<TextBlock
Grid.Row="2"
Grid.Column="0"
HorizontalAlignment="Right"
VerticalAlignment="Center"
FontSize="50"
Text="性别:" /> <TextBlock
Grid.Row="2"
Grid.Column="1"
HorizontalAlignment="Left"
VerticalAlignment="Center"
FontSize="50"
Foreground="#0078d4"
Text="女" /> <Button
Grid.Row="3"
Grid.ColumnSpan="2"
Width="300"
Margin="10"
Content="刷新"
FontSize="30"
FontWeight="Bold"
Background="Aqua"
BorderBrush="Azure"/>
</Grid>
</Page>
  • 5.以上界面的数据是写死的。我们需要将显示的地方绑定我们的数据。在绑定之前先建一个ViewModel文件夹。为了和MainView界面对应,要再添加一个MainViewVM类,在此类中我们使用刚创建的ClassMode数据模型,并在构造函数中初始化以下信息。
   public class MainViewVM
{
private ClassModel _classM; public ClassModel ClassM
{
get { return _classM; }
set { _classM = value; }
}
public MainViewVM()
{
ClassM = new ClassModel();
ClassM.Name = "王刚";
ClassM.Age = 10;
ClassM.Sex = "男";
}
}
  • 6.在MainView界面绑定ClassM的属性就行。
 <TextBlock
Grid.Row="0"
Grid.Column="1"
HorizontalAlignment="Left"
VerticalAlignment="Center"
FontSize="50"
Foreground="#0078d4"
Text="{Binding ClassM.Name}" />

但是这时候运行项目,发现什么数据也没有。

这是因为数据和界面都有了,我们并没有把他们关联在一起。要把View(MainView)与ViewModel(MainViewVM)关联一起。在MainView.xaml.cs里添加using WPFMVVM.ViewModel引用。再指定MainView的DataContext即可:

using WPFMVVM.ViewModel;
namespace WPFMVVM.View
{
public partial class MainView : Page
{
public MainView()
{
InitializeComponent();
this.DataContext = new MainViewVM();
}}}

启动解决方案,发现数据已经绑定上去了。

二.属性变更

  • 1.MVVM是数据驱动的,我们现在改变以下属性数据,看看界面效果。先简单的给button添加一个click事件:
   <Button
Grid.Row="3"
Grid.ColumnSpan="2"
Width="300"
Margin="10"
Content="刷新"
FontSize="30"
FontWeight="Bold"
Background="Aqua"
BorderBrush="Azure"
Click="Button_Click"/>

public partial class MainView : Page
{
MainViewVM mainViewVM;
public MainView()
{
InitializeComponent();
mainViewVM = new MainViewVM();
this.DataContext = mainViewVM;
} private void Button_Click(object sender, RoutedEventArgs e)
{
mainViewVM.ClassM.Name = "王大康";
mainViewVM.ClassM = mainViewVM.ClassM;//需要再次给ClassM复制才会触发界面刷新
}
}
  • 2.我们还需要让属性具有通知界面更新的能力。WPF中让属性具备通知更新的能力,要让ViewModel继承类型INotifyPropertyChanged,并实现PropertyChanged属性。此例MainViewVM添加如下:
    public class MainViewVM : INotifyPropertyChanged
{
public event PropertyChangedEventHandler? PropertyChanged; private void RaisePropertyChange(string propertyName)
{
PropertyChangedEventHandler hander = PropertyChanged;
if (hander != null)
{
hander(this, new PropertyChangedEventArgs(propertyName));
}
}
  • 3.完成以上步骤,我们还需要在ViewModel的数据属性set中调用更新界面的方法RaisePropertyChanged:
        public ClassModel ClassM
{
get { return _classM; }
set
{
_classM = value;
RaisePropertyChange(nameof(ClassM));
}
}

现在点击Button按钮,可以实现信息的刷新!

三.点击事件

  • 1.WPF给我们提供了Command属性,当然在MVVM模式下我们要用Command替换Click方法:
        <Button
Grid.Row="3"
Grid.ColumnSpan="2"
Width="300"
Margin="10"
Content="刷新"
FontSize="30"
FontWeight="Bold"
Background="Aqua"
BorderBrush="Azure"
Command="{Binding ClickAction}"
/>
  • 2.要实现绑定的ClickAction方法,需要继承ICommand接口。我们可以自己创建类型去实现 CanExecute、Execute、CanExecuteChanged接口。

    下面我们在MainViewVM.cs新建一个RealayCommand类:
  public class RelayCommand<T> : ICommand
{
/// <summary>
/// 命令是否执行
/// </summary>
readonly Func<bool> _canExecute;
/// <summary>
/// 命令执行的方法
/// </summary>
readonly Action<T> _execute;
/// <summary>
/// 命令的构造函数
/// </summary>
/// <param name="canExecute"></param>
/// <param name="execute"></param>
public RelayCommand(Func<bool> canExecute, Action<T> execute)
{
_canExecute = canExecute;
_execute = execute;
}
/// <summary>
/// 判断命令是否可执行
/// </summary>
/// <param name="parameter"></param>
/// <returns></returns>
public bool CanExecute(object? parameter)
{
if (_canExecute == null)
{
return true;
}
return _canExecute();
}
/// <summary>
/// 执行命令
/// </summary>
/// <param name="parameter"></param>
public void Execute(object parameter)
{
_execute((T)parameter);
}
/// <summary>
/// 事件追加、移除
/// </summary>
public event EventHandler? CanExecuteChanged
{
add
{
if (_canExecute != null)
{
CommandManager.RequerySuggested += value;
}
}
remove
{
if (_canExecute != null)
{
CommandManager.RequerySuggested -= value;
}
}
}
}

这个类接收两个参数,一个是命令执行的方法,另一个是返回值方法。

  • 3.我们在MainViewVM下编写以下代码调用RelayCommand:
        /// <summary>
/// 创建Button绑定的命令
/// </summary>
public ICommand ClickAction
{
get
{
return new RelayCommand<object>(CanUpdateExecute, UpdateNameExecute);
}
}
/// <summary>
/// 命令是否可执行
/// </summary>
/// <returns></returns>
bool CanUpdateExecute()
{
return true;
}
/// <summary>
/// 命令执行的方法
/// </summary>
/// <param name="parameter"></param>
void UpdateNameExecute(object parameter)
{
ClassM.Name = "王大康";
ClassM = ClassM;
}

此时我们运行程序,点击按钮,可以看到界面可以内容可以实现刷新了!

我们创建的RealayCommand是泛型类,执行命令的时候可以从界面把参数传过来。例如我们可以在Button添加CommandParameter="{Binding RelativeSource={RelativeSource Mode=Self}}"属性,然后把信息传到后台使用:

前端代码:
<Button
Grid.Row="3"
Grid.ColumnSpan="2"
Width="300"
Margin="10"
Content="刷新"
FontSize="30"
FontWeight="Bold"
Background="Aqua"
BorderBrush="Azure"
Command="{Binding ClickAction}"
CommandParameter="{Binding RelativeSource={RelativeSource Mode=Self}}"/>
button 绑定的命令:
void UpdateNameExecute(object parameter)
{
Button? button =parameter as Button;//parameter前端绑定的Button
if (button.Background !=Brushes.BlanchedAlmond)
{
button.Background = Brushes.BlanchedAlmond ;
ClassM.Name = "王大康";
ClassM = ClassM;
}
else
{
button.Background=Brushes.DarkBlue;
ClassM.Name = "李小康";
ClassM = ClassM;
}
}

到此,简单的MVVM数据绑定完成


其实吧大可不必那么麻烦,我们可以安装引用GalaSoft.MvvmLight库,RaisePropertyChange/RelayCommand都不用自定义了,省事了。如下是引用库后的MainViewVM代码:

using GalaSoft.MvvmLight;
using GalaSoft.MvvmLight.Command;
using System.Windows.Controls;
using System.Windows.Input;
using System.Windows.Media;
using WPFMVVM.Model; namespace WPFMVVM.ViewModel
{
public class MainViewVM : ViewModelBase
{
private ClassModel _classM;
public ClassModel ClassM
{
get { return _classM; }
set
{
_classM = value;
RaisePropertyChanged(nameof(ClassM));
}
}
public MainViewVM()
{
ClassM = new ClassModel();
ClassM.Name = "王xiao刚";
ClassM.Age = 10;
ClassM.Sex = "男";
} /// <summary>
/// 创建Button绑定的命令
/// </summary>
public ICommand ClickAction
{
get
{
return new RelayCommand<object>(UpdateNameExecute);
}
}
/// <summary>
/// 命令执行的函数
/// </summary>
/// <param name="parameter"></param>
private void UpdateNameExecute(object parameter)
{
Button? button = parameter as Button;
if (button.Background != Brushes.BlanchedAlmond)
{
button.Background = Brushes.BlanchedAlmond;
ClassM.Name = "王大康";
ClassM = ClassM;
}
else
{
button.Background = Brushes.DarkBlue;
ClassM.Name = "李小康";
ClassM = ClassM;
}
}
}
}

[WPF]MVVM的数据绑定的更多相关文章

  1. WPF MVVM从入门到精通3:数据绑定

    原文:WPF MVVM从入门到精通3:数据绑定   WPF MVVM从入门到精通1:MVVM模式简介 WPF MVVM从入门到精通2:实现一个登录窗口 WPF MVVM从入门到精通3:数据绑定 WPF ...

  2. WPF/MVVM 快速开始指南(译)(转)

    WPF/MVVM 快速开始指南(译) 本篇文章是Barry Lapthorn创作的,感觉写得很好,翻译一下,做个纪念.由于英文水平实在太烂,所以翻译有错或者译得不好的地方请多指正.另外由于原文是针对W ...

  3. WPF+MVVM学习总结 DataGrid简单案例

    一.WPF概要 WPF(Windows Presentation Foundation)是微软推出的基于Windows 的用户界面框架,属于.NET Framework 3.0的一部分.它提供了统一的 ...

  4. 转载:WPF MVVM之INotifyPropertyChanged接口的几种实现方式

    原文地址:http://www.cnblogs.com/xiwang/ 序言 借助WPF/Sliverlight强大的数据绑定功能,可以比实现比MFC,WinForm更加优雅轻松的数据绑定.但是在使用 ...

  5. WPF MVVM模式的一些理解

    /*本文转自 http://www.cnblogs.com/sirkevin/archive/2012/11/28/2793471.html */ 使用WPF+Mvvm开发一年多,期间由于对Mvvm模 ...

  6. WPF自学入门(十)WPF MVVM简单介绍

     前面文章中,我们已经知道,WPF技术的主要特点是数据驱动UI,所以在使用WPF技术开发的过程中是以数据为核心的,WPF提供了数据绑定机制,当数据发生变化时,WPF会自动发出通知去更新UI. 我们不管 ...

  7. wpf mvvm 实例

    1.程序结构如图所示: 2.Model实现 在Model文件夹下新建业务类StudentModel,代码如下: public class StudentModel : INotifyPropertyC ...

  8. 【转】【WPF】WPF MVVM 简单实例

    1 新建WPF 应用程序WPFMVVMExample 程序结构如下图所示. 2 Model实现 在Model文件夹下新建业务类StudentModel(类文件StudentModel.cs),类的详细 ...

  9. WPF MVVM从入门到精通8:数据验证

    原文:WPF MVVM从入门到精通8:数据验证 WPF MVVM从入门到精通1:MVVM模式简介 WPF MVVM从入门到精通2:实现一个登录窗口 WPF MVVM从入门到精通3:数据绑定 WPF M ...

  10. WPF MVVM从入门到精通6:RadioButton等一对多控件的绑定

    原文:WPF MVVM从入门到精通6:RadioButton等一对多控件的绑定   WPF MVVM从入门到精通1:MVVM模式简介 WPF MVVM从入门到精通2:实现一个登录窗口 WPF MVVM ...

随机推荐

  1. elementui中 table表格 合并表头

    需要实现的效果如图,表格头部合并成一排. 因为总共是4列,所以colSpan =4表示合并4列 头部给个高度,居中一下就ok啦

  2. [深度学习] Contractive Autoencoder

    ​  转载于DeepLearning: Contractive Autoencoder - dupuleng - 博客园 一.雅克比矩阵 雅克比矩阵是一阶偏导,假设(x1,x2,....,xn)到(y ...

  3. [seaborn] seaborn学习笔记1-箱形图Boxplot

    文章目录 1 箱形图Boxplot 1. 基础箱形图绘制 Basic boxplot and input format 2. 自定义外观 Custom boxplot appearance 3. 箱型 ...

  4. 使用java代码调用rabbitmq接口进行新增编辑mq用户、虚拟机vhost、动态创建交换机exchange、队列queue以及设置权限,绑定vhost与exchange等操作

    使用java代码操作rabbitmq时,首先需要一个有创建用户等权限的管理员账号,需要在rabbitmq的后台管理页面手动创建这个账号,系统推荐的这几个tag可以让账号有rabbitmq后台管理页面的 ...

  5. Codeforces Round #842 (Div. 2) A-D

    比赛链接 A 题意 给一个数 \(k\) 找到最大的 \(x\) ,满足 \(1 \leq x < k\) 且 \(x!+(x-1)!\) 是 \(k\) 的倍数. 题解 知识点:数学. 猜测 ...

  6. js鼠标轨迹特效

    今天无意中访问到了开源社区 (apiopen.top)的主界面,发现鼠标跟随的特效不错(残留轨迹),弄下来玩玩 上代码 整合后只需要两部分,导入JS依赖后,在html 添加 id 为 mouseCan ...

  7. Java基础学习笔记-常量与变量♪(^∇^*)

    常量与变量相同点 都有作用域,跟JS差不多, 变量的作用域:一对{ }之间有效 1.局部 2.全局 2.1.属于类的量(类常量和类变量) 2.2.属于实例的量(实例常量和实例变量) • 前面都可加权限 ...

  8. [Codeforces Round #816 (Div. 2)] D. 2+ doors

    这次Div.2比之前我打的有些要难啊,前三道题就耗了好多时间,D题干脆摆烂了... 还是太逊了 对于一个\(x\),有\(x|y_i=z_i\),那么我们设\(num[x]=z_1\)&\(z ...

  9. 静态代码块-数组工具类Arrays

    静态代码块 静态代码块: 定义在成员位置,使用static修饰的代码块{}. 位置:类中方法外. 执行:随着类的加载而执行且执行一次,优先于main方法和构造方法的执行 格式: public clas ...

  10. 12月22日内容总结——django中间件的三个了解要求的方法、基于django中间件的功能设计、cookie与session

    目录 一.django中间件三个了解的方法 二.django中间件五个方法的执行流程详解 三.基于django中间件的功能设计 功能设计介绍 如何利用字符串导入模块 功能模拟 四.cookie与ses ...