[WPF]MVVM的数据绑定
啥是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的数据绑定的更多相关文章
- WPF MVVM从入门到精通3:数据绑定
		原文:WPF MVVM从入门到精通3:数据绑定 WPF MVVM从入门到精通1:MVVM模式简介 WPF MVVM从入门到精通2:实现一个登录窗口 WPF MVVM从入门到精通3:数据绑定 WPF ... 
- WPF/MVVM 快速开始指南(译)(转)
		WPF/MVVM 快速开始指南(译) 本篇文章是Barry Lapthorn创作的,感觉写得很好,翻译一下,做个纪念.由于英文水平实在太烂,所以翻译有错或者译得不好的地方请多指正.另外由于原文是针对W ... 
- WPF+MVVM学习总结 DataGrid简单案例
		一.WPF概要 WPF(Windows Presentation Foundation)是微软推出的基于Windows 的用户界面框架,属于.NET Framework 3.0的一部分.它提供了统一的 ... 
- 转载:WPF MVVM之INotifyPropertyChanged接口的几种实现方式
		原文地址:http://www.cnblogs.com/xiwang/ 序言 借助WPF/Sliverlight强大的数据绑定功能,可以比实现比MFC,WinForm更加优雅轻松的数据绑定.但是在使用 ... 
- WPF MVVM模式的一些理解
		/*本文转自 http://www.cnblogs.com/sirkevin/archive/2012/11/28/2793471.html */ 使用WPF+Mvvm开发一年多,期间由于对Mvvm模 ... 
- WPF自学入门(十)WPF MVVM简单介绍
		前面文章中,我们已经知道,WPF技术的主要特点是数据驱动UI,所以在使用WPF技术开发的过程中是以数据为核心的,WPF提供了数据绑定机制,当数据发生变化时,WPF会自动发出通知去更新UI. 我们不管 ... 
- wpf mvvm 实例
		1.程序结构如图所示: 2.Model实现 在Model文件夹下新建业务类StudentModel,代码如下: public class StudentModel : INotifyPropertyC ... 
- 【转】【WPF】WPF MVVM 简单实例
		1 新建WPF 应用程序WPFMVVMExample 程序结构如下图所示. 2 Model实现 在Model文件夹下新建业务类StudentModel(类文件StudentModel.cs),类的详细 ... 
- WPF MVVM从入门到精通8:数据验证
		原文:WPF MVVM从入门到精通8:数据验证 WPF MVVM从入门到精通1:MVVM模式简介 WPF MVVM从入门到精通2:实现一个登录窗口 WPF MVVM从入门到精通3:数据绑定 WPF M ... 
- WPF MVVM从入门到精通6:RadioButton等一对多控件的绑定
		原文:WPF MVVM从入门到精通6:RadioButton等一对多控件的绑定 WPF MVVM从入门到精通1:MVVM模式简介 WPF MVVM从入门到精通2:实现一个登录窗口 WPF MVVM ... 
随机推荐
- Scrum敏捷开发方法实践
			前言 作者所在的公司在项目开发的过程中采用着当下互联网公司中流行的小步快跑开发策略,特别借鉴了敏捷开发中的迭代递增思想来指导项目的开发.我们经过对相关敏捷开发方法的调查研究,最终采用了Scrum敏 ... 
- war包形式安装jenkins
			(1)下载war包 输入命令:java -jar jenkins.war --httpPort=8080,更改端口 重新登录之后,输入密码创建用户等完成设置 (2)结合Tomcat安装: 将jenki ... 
- Graph Neural Network——图神经网络
			本文是跟着李沐老师的论文精度系列进行GNN的学习的,详细链接请见:零基础多图详解图神经网络(GNN/GCN)[论文精读] 该论文的标题为<A Gentle Introduction to Gra ... 
- 【FAQ】申请Health Kit权限的常见问题及解答
			华为运动健康服务(HUAWEI Health Kit)提供原子化数据开放,用户数据被授权获取后,应用可通过接口访问运动健康数据,对相关数据进行增.删.改.查等操作.这篇文章汇总了申请开通Health ... 
- 【Spring专题】「开发指南」夯实实战基础功底之解读logback-spring.xml文件的详解实现
			logback的maven配置 <dependency> <groupId>org.slf4j</groupId> <artifactId>slf4j- ... 
- JavaScript:代码细节和良好编码习惯
			这些细节,与语法无关,仅仅是编写代码时需要注意的最最基本的细节和一些良好编码习惯. 注释代码 注释代码分为单行注释和多行注释,如下所示: 严格区分大小写 JS的代码时严格区分大小写的,变量a和A是不同 ... 
- JavaScript:代码应该编写在哪里?
			我们可以将JS的代码,编写在三个地方. 但是无论编写在哪里,最后它都会嵌入进网页代码中,被浏览器执行. 编写在script标签中 我们可以直接在HTML的script标签中,编写大段JS代码. 编写在 ... 
- vulnhub靶场之HACKABLE: III
			准备: 攻击机:虚拟机kali.本机win10. 靶机:Hackable: III,下载地址:https://download.vulnhub.com/hackable/hackable3.ova,下 ... 
- 问一个 Windows 窗口的 Capture 问题
			好久没写了,上来先问一个问题...羞射... 有 A.B 两个窗口,A 是 B 的 Owner,B 不激活不抢焦点.在 B 的 WM_LBUTTONDOWN 的时候,设置 A 窗口为 Capture: ... 
- MySQL 不四舍五入取整、取小数、四舍五入取整、取小数、向下、向上取整
			总结了MySQL中取整和取小数中遇到的问题和解决的几个方法:不四舍五入取整.取小数.四舍五入取整.取小数.向下.向上取整. 其中: 不四舍五入取整(截取整数部分)就是'向下取整': 除了用trunca ... 
