WPF MVVM入门系列教程(三、数据绑定)

本文主要介绍WPF的数据绑定(Data Binding)功能,如果你已经熟悉本文的内容,可以跳过并直接阅读后面的文章。

什么是数据绑定

我们先来看一下MSDN上的说明:

数据绑定是在应用 UI 与其显示的数据之间建立连接的过程。 如果绑定具有正确的设置,并且数据提供适当的通知,则在数据更改其值时,绑定到该数据的元素会自动反映更改。 数据绑定还意味着,如果元素中数据的外部表示形式发生更改,则基础数据可以自动进行更新以反映更改。

我们先不考虑技术细节 ,通俗点来说,可以理解为:

将控件的某个依赖属性(UI)(BindingTarget)绑定到某个数据(BindingSource)上,当数据进行更改时,绑定的依赖属性值会更新(UI更新)。而当依赖属性的值更改(UI更改)时,绑定的数据也会进行更改。

举个简单的例子:

例如TextBox控件有个依赖属性Text,它可以设置TextBox的显示内容。

然后我们有一个对象,对象里有个属性叫DisplayText, 将TextBox.Text属性绑定到这个对象的DisplayText属性上。

当我们在界面上对这个TextBox的文本进行编辑时,DisplayText属性会更新。反之,我们对DisplayText进行操作时,TextBox也会进行刷新 。

一些基础概念

通常情况下,每个绑定具有四个组件:

  • 绑定目标对象。
  • 目标属性。
  • 绑定源。
  • 指向绑定源中要使用的值的路径

例如TextBox控件有个依赖属性Text,然后我们有一个对象Object,对象里有个属性叫DisplayText, 将TextBox.Text属性绑定到这个对象的DisplayText属性上。

对应绑定的四个组件如下:

设置“值”
目标TextBox
目标属性Text
源对象Object
源对象值路径DisplayText

说明:

1、目标属性必须为依赖属性

      大多数 UIElement 属性都是依赖属性,而大多数依赖属性(只读属性除外)默认支持数据绑定。 只有从 DependencyObject 派生的类型才能定义依赖项属性。 所有 UIElement 类型从 DependencyObject 派生。

2、绑定源不限于自定义 .NET 对象。

绑定源对象不限于自定义 .NET 对象。 WPF 数据绑定支持 .NET 对象、XML 甚至是 XAML 元素对象形式的数据。

3、在建立绑定时,需要将绑定目标绑定到绑定源。 例如,如果要使用数据绑定在 ListBox 中显示List<T>的数据,则需要将 ListBox 绑定到 List<T>数据。

为什么要使用数据绑定

在第一篇文章中,介绍MVVM的基础概念时,使用了上面这张图,来介绍MVVM的原理。可以看到ViewModel层和View层的交互方式里,有DataBinding

视图为用户提供两项服务:数据展示和与数据交互。数据展示通过读取数据并以某种格式显示,数据交互指的是编辑现有数据或添加新数据。而实现这一功能的基础就是数据绑定。

数据上下文(DataContext)

当在 XAML 元素上声明数据绑定时,WPF会通过查看它的 DataContext 属性来解析数据绑定。在MVVM开发中,就是将ViewModel赋值给整个窗口的DataContext属性。

如果未设置元素的 DataContext 属性,则将检查父元素的 DataContext 属性,依此类推,直到 XAML 对象树的根。 简而言之,除非在对象上显式设置,否则用于解析绑定的数据上下文将继承自父级。

当 DataContext 属性发生更改时,所以的绑定值都会进行刷新。

我们先通过一个简单的例子演示一下:

首先我们创建一个窗口,放置一个TextBox控件,然后将Text属性绑定到DisplayText

 1 <Window x:Class="BasicDataContextDemo.MainWindow"2         xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"3         xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"4         xmlns:d="http://schemas.microsoft.com/expression/blend/2008"5         xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"6         xmlns:local="clr-namespace:BasicDataContextDemo"7         mc:Ignorable="d"8         Title="MainWindow" Height="450" Width="800" Name="window">9     <Grid Name="grid">
10         <TextBox Name="textbox" HorizontalAlignment="Center" VerticalAlignment="Center" Width="200" Text="{Binding DisplayText}"></TextBox>
11     </Grid>
12 </Window>

然后我们创建一个数据对象,其中包含一个DisplayText属性:

 1   public class MyData2   {3       private string displayText = "HelloWorld";4 5       public string DisplayText6       {7           get => displayText;8           set => displayText = value;9       }
10   }

创建一个MyData对象,并绑定到DataContext

 1  public partial class MainWindow : Window2  {3      public MainWindow()4      {5          InitializeComponent();6 7          var myData = new MyData();8          this.textbox.DataContext = myData;9      }
10  }

运行程序可以看到文本框已经被赋值"HelloWorld"

数据流的方向

在进行绑定时,可以通过Mode属性来设置数据流的方向。WPF中支持以下几种模式。

OneWay模式 (属性 -> UI)

  • 通过 OneWay 绑定,对源属性的更改会自动更新目标属性,但对目标属性的更改不会传播回源属性。 如果绑定的控件为隐式只读,则此类型的绑定适用。 

          如果无需监视目标属性的更改,则使用 OneWay 绑定模式可避免 TwoWay 绑定模式的系统开销。

          用前面的例子来说:

          我们将MyDataDisplayText属性绑定到TextBox.Text属性上,

          当修改MyData.DisplayText属性时,界面会进行更新。

          但是在TextBox进行编辑时,MyData.DisplayText属性不会被更新。

TwoWay模式(默认)(UI <=> 属性)

  • 通过 TwoWay 绑定,更改源属性或目标属性时会自动更新另一方。 此类型的绑定适用于可编辑窗体或其他完全交互式 UI 方案。 大多数属性默认为 OneWay 绑定,但某些依赖属性(通常为用户可编辑控件的属性,例如 TextBox.Text 和 CheckBox.IsChecked)默认为 TwoWay 绑定。

          用前面的例子来说:

          我们将MyDataDisplayText属性绑定到TextBox.Text属性上,

          当修改MyData.DisplayText属性时,界面会进行更新。

          当在TextBox进行编辑时,MyData.DisplayText属性也会被更新。

OneWayToSource模式

  • OneWayToSource 绑定与 OneWay 绑定相反;当目标属性更改时,它会更新源属性。(UI -> 属性)

         用前面的例子来说:

         我们将MyDataDisplayText属性绑定到TextBox.Text属性上,

          当修改MyData.DisplayText属性时,界面不会进行更新。

          当在TextBox进行编辑时,MyData.DisplayText属性会被更新。

OntTime模式

  • OneTime 绑定未在图中显示,该绑定会使源属性初始化目标属性,但不传播后续更改。 如果数据上下文发生更改,或者数据上下文中的对象发生更改,则更改不会在目标属性中反映。 如果适合使用当前状态的快照或数据实际为静态数据,则此类型的绑定适合。 如果你想使用源属性中的某个值来初始化目标属性,且提前不知道数据上下文,则此类型的绑定也有用。 此模式实质上是 OneWay 绑定的一种简化形式,它在源值不更改的情况下提供更好的性能。

使用示例如下:

1     <TextBox Text="{Binding DisplayText,Mode=TwoWay}"></TextBox>

属性更改通知

在使用MVVM模式进行开发时,属性更改通知是一个很关键的知识点。

让我们再次看到前面的示例,将TextBox.Text绑定到MyData.DisplayName

1 var myData = new MyData();
2 this.textbox.DataContext = myData;

此时我们会发现一个问题,即使我们使用了TwoWay模式绑定,当我们修改MyData.DisplayName值时,界面并不会更新。

1  var myData = this.textbox.DataContext as MyData;
2  myData.DisplayText = "tragedy";  //ui not update

如何实现属性更改通知呢?我们需要对MyData进行一些改造。

需要修改的地方如下

1、将MyData实现 INotifyPropertyChanged 接口。

2、当属性更改时,调用PropertyChanged事件进行通知。

完整的示例如下:

 1     public class MyData2 : INotifyPropertyChanged2     {3         private string displayText2 = "HelloWorld";4 5         public string DisplayText26         {7             get => displayText2;8             set9             {
10                 displayText2 = value;
11 
12                 PropertyChanged?.Invoke(this,new PropertyChangedEventArgs("DisplayText2"));
13 
14                 //or
15                 //OnPropertyChanged();
16             }
17         }
18 
19         public event PropertyChangedEventHandler? PropertyChanged;
20 
21 
22         protected void OnPropertyChanged([CallerMemberName] string name = null)
23         {
24             PropertyChanged?.Invoke(this, new PropertyChangedEventArgs(name));
25         }
26     }

此时我们再修改属性的值,界面也会同步刷新。

触发源更新的因素

在进行绑定时,可以通过UpdateSourceTrigger属性来设置如何触发源更新。

通俗点来说,就是当界面上的值更改了,例如我编辑了TextBox,何时去更改绑定的属性值呢?这种情况就可以通过UpdateSourceTrigger属性来设置。

需要注意的是只有TwoWay 或 OneWayToSource 模式的绑定会生效,因为只有这两种模式的数据流是从UI到属性。

支持以下几种模式

Default

大多数依赖属性的默认值是 PropertyChanged,但是 Text 属性的默认值是 LostFocus

PropertyChanged

每当绑定目标属性发生变化时,立即更新绑定源。

LostFocus

当绑定目标元素失去焦点时更新绑定源。

Explicit

仅在调用 UpdateSource() 方法时更新绑定源。

示例如下:

1   <TextBox Text="{Binding Text,UpdateSourceTrigger=PropertyChanged}"></TextBox>

示例代码

WPF-MVVM-Beginner/3_DataBinding/DataBinding at main · zhaotianff/WPF-MVVM-Beginner · GitHub

参考资料:

数据绑定概述 - WPF .NET | Microsoft Learn

如何:实现属性更改通知 - WPF .NET Framework | Microsoft Learn

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.xdnf.cn/news/8984.html

如若内容造成侵权/违法违规/事实不符,请联系一条长河网进行投诉反馈,一经查实,立即删除!

相关文章

关于Dell r730xd 老服务器的阵列卡 配置系统盘RAID 1

这里写自定义目录标题 关于Dell r730xd 老服务器的阵列卡 配置系统盘RAID 1操作步骤 关于Dell r730xd 老服务器的阵列卡 配置系统盘RAID 1 操作步骤 -开机后 按 Ctrl R 进入 RAID卡 配置界面&#xff0c;如下&#xff1a;-下面图片是 服务器中硬盘都已经准备好&#xff0c;并…

Qt Udp的组播(多播)、广播和单播

UDP通讯的基本概念和特点‌ UDP&#xff08;User Datagram Protocol&#xff0c;用户数据报协议&#xff09;是‌TCP/IP协议族中的一种无连接协议&#xff0c;主要用于那些对实时性要求较高而可靠性要求较低的应用场景。UDP的主要特点包括&#xff1a; ‌无连接‌&#xff1a;…

算法每日双题精讲——双指针(快乐数,盛最多水的容器)

&#x1f31f;快来参与讨论&#x1f4ac;&#xff0c;点赞&#x1f44d;、收藏⭐、分享&#x1f4e4;&#xff0c;共创活力社区。 &#x1f31f; 别再犹豫了&#xff01;快来订阅我们的算法每日双题精讲专栏&#xff0c;一起踏上算法学习的精彩之旅吧&#xff01;&#x1f4aa;…

C语言 | Leetcode C语言题解之第551题学生出勤记录I

题目&#xff1a; 题解&#xff1a; bool checkRecord(char* s) {int absents 0, lates 0;int n strlen(s);for (int i 0; i < n; i) {char c s[i];if (c A) {absents;if (absents > 2) {return false;}}if (c L) {lates;if (lates > 3) {return false;}} els…

【未解决】vite反向代理问题

文章目录 可行网页直接访问&#xff0c;数据正常返回不使用反向代理&#xff0c;直接用axios可以得到数据postman测试也正常 不行-vite反向代理出问题case1命令行测试 可行 网页直接访问&#xff0c;数据正常返回 在地址栏输入 https://api.binance.com/api/v3/ticker/price?…

github使用基础

要通过终端绑定GitHub账号并进行文件传输&#xff0c;你需要使用Git和SSH密钥来实现安全连接和操作。以下是一个基本流程&#xff1a; 设置GitHub和SSH 检查Git安装 通过终端输入以下命令查看是否安装Git&#xff1a; bash 复制代码 git --version配置Git用户名和邮箱 bash …

9_api_intro_imagerecognition_ocr2word

通用图片 OCR 到 Word API 数据接口 高可用图像识别引擎&#xff0c;基于机器学习&#xff0c;超精准识别率。 1. 产品功能 通用的识别接口&#xff0c; 支持多种图片格式&#xff1b;支持中英文字符混合识别&#xff1b;支持 Base64 以及网络地址传参&#xff1b;基于机器学习…

深度优先搜索之全排列问题(C语言版)

本文的一些参考&#xff1a; DFS (深度优先搜索) 算法详解 模板 例题&#xff0c;这一篇就够了_dfs算法-CSDN博客 首先把深度优先搜索算法的基本概论摆出来 深度优先搜索算法&#xff08;Depth First Search&#xff0c;简称DFS&#xff09;&#xff1a; 一种用于遍历或搜…

如何防止苹果MacOS进入休眠状态

前言 远程控制的时候&#xff0c;发现MacOS已经进入了休眠状态。如何设置MacOS&#xff0c;防止其进入休眠状态&#xff0c;这样才能远程控制。 1、进入系统偏好设置 显示器自动关闭了不要紧。只要操作系统不进入休眠就可以。

云计算:定义、类型及对企业的影响

&#x1f493; 博客主页&#xff1a;瑕疵的CSDN主页 &#x1f4dd; Gitee主页&#xff1a;瑕疵的gitee主页 ⏩ 文章专栏&#xff1a;《热点资讯》 云计算&#xff1a;定义、类型及对企业的影响 云计算&#xff1a;定义、类型及对企业的影响 云计算&#xff1a;定义、类型及对企…

Pr 视频过渡:沉浸式视频

效果面板/视频过渡/沉浸式视频 Video Transitions/Immersive Video Adobe Premiere Pro 的视频过渡效果中&#xff0c;沉浸式视频 Immersive Video效果组主要用于 VR 视频剪辑之间的过渡。 自动 VR 属性 Auto VR Properties是所有 VR 视频过渡效果的通用选项。 默认勾选&#x…

ArcGIS Pro SDK Addin-DAML

ArcGIS Pro SDK Addin-DAML 文章目录 ArcGIS Pro SDK Addin-DAML1 Panes: 重置窗格2 Button: 从功能区中移除核心按钮3 Button: 将新按钮插入功能区上的现有组4 Menu: 在图层上下文菜单中插入一个新按钮5 Menu: 在 Map Container 上下文菜单中插入新菜单6 Menu: 在2D Map上下文…

【电机控制器】STC8H1K芯片——ADC电压采集

【电机控制器】STC8H1K芯片——ADC电压采集 文章目录 [TOC](文章目录) 前言一、ADC1.ADC初始化1.ADC_CONTR2.ADCCFG3.ADCTIM4.代码 2.ADC读取1.ADC_RES、ADC_RESL2.代码 3.VREF电压读取——MCU工作电压1.MCU工作电压计算公式2.代码 4.ADC被转换通道的输入电压读取1.ADC被转换通…

SpringBoot基础系列学习(三):日志

文章目录 一丶日志控制台介绍二丶日志的用法三丶日志级别四丶配置文件参数及介绍五丶slf4j 一丶日志控制台介绍 只要引用了spring-boot-starter依赖,就无需引入日志依赖,里面自带了logging依赖,默认情况下,springBoot使用Logback来记录日志,并用INFO级别输出到控制台 二丶日…

鸿蒙系统:安卓与iOS的强劲对手

随着科技的迅猛发展&#xff0c;“纯血鸿蒙”系统HarmonyOS Next 5.0系统的推出引起了业界的广泛关注。用户们对这一新系统充满好奇&#xff0c;急切地想要体验其带来的变革。鸿蒙系统以其创新的设计和技术支持&#xff0c;成为与安卓和iOS并列的第三大操作系统。 鸿蒙系统的独…

Redis - 哨兵(Sentinel)

Redis 的主从复制模式下&#xff0c;⼀旦主节点由于故障不能提供服务&#xff0c;需要⼈⼯进⾏主从切换&#xff0c;同时⼤量 的客⼾端需要被通知切换到新的主节点上&#xff0c;对于上了⼀定规模的应⽤来说&#xff0c;这种⽅案是⽆法接受的&#xff0c; 于是Redis从2.8开始提…

Golang | Leetcode Golang题解之第552题学生出勤记录II

题目&#xff1a; 题解&#xff1a; const mod int 1e9 7type matrix [6][6]intfunc (a matrix) mul(b matrix) matrix {c : matrix{}for i, row : range a {for j : range b[0] {for k, v : range row {c[i][j] (c[i][j] v*b[k][j]) % mod}}}return c }func (a matrix) p…

放电电阻是什么

放电电阻&#xff0c;顾名思义&#xff0c;就是用于放电的电阻。在电路中&#xff0c;当电流突然增大时&#xff0c;如果没有适当的电阻来限制电流&#xff0c;就可能导致电路损坏。因此&#xff0c;放电电阻的作用就是在电路中起到限制电流的作用&#xff0c;防止电路因电流过…

CelebV-Text——从文本生成人脸视频的数据集

概述 近年来&#xff0c;生成模型在根据文本生成和编辑视频方面受到了广泛关注。然而&#xff0c;由于缺乏合适的数据集&#xff0c;生成人脸视频领域仍然是一个挑战。特别是&#xff0c;生成的视频帧质量较低&#xff0c;与输入文本的相关性较弱。在本文中&#xff0c;我们通…

【51单片机数码管的控制开机时前四位数码管显示0000,每按下一次按键后松开数字加121,当数字大于等于8888时清零。】2022-3-18

缘由51单片机数码管的控制-嵌入式-CSDN问答 #include "REG52.h" sbit K1 P3^1; unsigned char code SmZiFu[]{63,6,91,79,102,109,125,7,127,111,128,119,124,57,94,121,113};//0-9. void smxs(unsigned char mz, unsigned char w) {unsigned char Xd0;P2255;P2255…