当前位置: 首页 > news >正文

WPF Binding 绑定

绑定是 wpf 开发中的精髓,有绑定才有所谓的数据驱动。

1 . 背景

目前 wpf 界面可视化的控件,继承关系如下,
在这里插入图片描述

控件的数据绑定,基本上都要借助于 FrameworkElement 的 DataContext 属性。

只有先设置了控件的 DataContext 属性,再设置绑定才能生效(TemplateBinding、使用 RelativeSource、后台 new Binding、静态资源等特殊情况另外讨论)。

2. 绑定的参与对象

绑定过程涉及到两个重要的对象

  1. 绑定目标

数据源绑定到的 依赖属性,只有依赖属性才能作为绑定目标。例如 TextBlock.TextPropertyItemsControl.ItemsSourceProperty

不是只有控件才有依赖属性,普通 CLR 类也可以包括依赖属性。

  1. 绑定源

依赖属性绑定的数据源,例如类中的 属性、界面中的 资源 等。

3. 使用 DataContext 的数据绑定

定义一个包含 2 个只读属性的类型,

public class SampleViewModel
{public string Title { get; }public int Count { get; }public SampleViewModel(){Title = "Hello~";Count = 100;}
}

界面以 UserControl 为例,在构造函数中设置整个界面的 DataContext。

DataContext 会自动从父类向子类传递,子元素也可重新设置 DataContext 属性为其它值。

设置界面控件的 DataContext,

public partial class BindingView : UserControl
{public BindingView(){InitializeComponent();DataContext = new SampleViewModel();}
}

3.1 在前端代码中设置绑定

<UserControlx:Class="WpfApp1.Views.BindingView"xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"xmlns:d="http://schemas.microsoft.com/expression/blend/2008"xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"xmlns:viewModels="clr-namespace:WpfApp1.ViewModels"d:DataContext="{d:DesignInstance viewModels:SampleViewModel}"d:DesignHeight="450"d:DesignWidth="800"mc:Ignorable="d"><Grid Background="DeepPink" Width="100" Height="100"><StackPanel><TextBlock Margin="4" Text="{Binding Title}" /><TextBlock Margin="4" Text="{Binding Count}" /></StackPanel></Grid>
</UserControl>

显示结果,
在这里插入图片描述

3.2 在后端代码中设置绑定

将前端绑定代码去掉,并设置控件的 x:Name 属性值,

<Grid Background="DeepPink" Width="100" Height="100"><StackPanel><TextBlock x:Name="Text1" Margin="4" /><TextBlock x:Name="Text2" Margin="4" /></StackPanel>
</Grid>

在后端中手动绑定,

public BindingView()
{InitializeComponent();DataContext = new SampleViewModel();//后台代码绑定var binding1 = new Binding("Title"){Source = this.DataContext,};var binding2 = new Binding("Count"){Source = this.DataContext,};this.Text1.SetBinding(TextBlock.TextProperty, binding1);this.Text2.SetBinding(TextBlock.TextProperty, binding2);
}

同样可以实现绑定。

上面的例子,绑定参与对象是:

绑定目标:TextBlock.TextProperty 依赖属性
绑定源:this.DataContext 即 SampleViewModel 实例
绑定路径:TitleCount

也可以简单点说,

绑定目标:TextBlock.TextProperty 依赖属性
绑定源: SampleViewModel 实例的 TitleCount 属性

一般推荐直接在前端绑定,有特殊业务需求才会在后台动态绑定。

4. 不使用 DataContext 的数据绑定

不设置 DataContext 的情况下, 也可以使用绑定,比如绑定界面控件或控件的属性、页面资源等。

xmlns:system="clr-namespace:System;assembly=mscorlib"
<UserControl.Resources><system:String x:Key="Content">我是静态资源</system:String>
</UserControl.Resources><Grid Background="DeepPink" Width="100" Height="100"><StackPanel><!-- 绑定 CLR 属性 --><TextBlock x:Name="Text1" Margin="4" Text="{Binding Title}" /><!-- 绑定控件 --><TextBlock x:Name="Text2" Margin="4" Text="" Tag="{Binding ElementName=Text1}" /><!-- 绑定控件属性 --><TextBlock x:Name="Text3" Margin="4" Text="{Binding ElementName=Text2, Path=Tag.Text}" /><!-- 绑定页面资源 --><TextBlock x:Name="Text4" Margin="4" Text="{Binding ., Source={StaticResource Content}}" /></StackPanel>
</Grid>

显示,
在这里插入图片描述

总结,

绑定目标必须是依赖属性,绑定源可以是依赖属性也可以是普通 CLR 属性、静态资源。

5. 绑定模式

以上演示的是简单的数据绑定,仅仅是用来显示,如果我还想把界面数据传回数据源,该如何操作?

以 CheckBox 勾选框为例,

<Grid Background="DeepPink" Width="100" Height="100"><CheckBox Margin="4" Content="Mark" IsChecked="{Binding Mark}" />
</Grid>

在这里插入图片描述
绑定源:

public class BindingModeViewModel
{private bool _mark = true; //默认勾选public bool Mark{get => _mark;set{if (_mark != value){_mark = value;Console.WriteLine($"Mark changed to {_mark}");}}}
}

取消勾选并再次勾选,结果,

Mark changed to False
Mark changed to True

接下来对控件绑定做一些改动,

<CheckBox Margin="4" Content="Mark" IsChecked="{Binding Mark, Mode=OneWay}" />

发现操作 CheckBox,不再会打印信息了。那是因为设置绑定模式 Mode=OnWay 就表示只支持从数据源到界面目标的单向绑定。

绑定模式有如下几种,

public enum BindingMode
{TwoWay, //双向绑定OneWay, //单向绑定:从数据源到目标OneTime, //单次绑定:只绑定一次OneWayToSource, //单向绑定:从目标到数据源Default, //默认绑定:根据数据源和目标自动决定
}

所以,这里我把 Mode 设置为 TwoWay、OneWayToSource、Default(不设置就是默认绑定)都可以打印出来信息。

到此,演示了:

  1. 从数据源获取数据到目标(如 TextBlock)
  2. 从目标设置数据到数据源(如 CheckBox)

那如果,我要从数据源设置动态数据到目标,该如何操作?这就要用到一个接口。

6. INotifyPropertyChanged 接口

public interface INotifyPropertyChanged
{event PropertyChangedEventHandler PropertyChanged;
}

INotifyPropertyChanged 是一个接口,用于在属性值发生变化时通知绑定的客户端。在 WPF 应用程序中,这通常用于实现数据绑定,使得 UI 元素能够在源数据动态变化时自动更新。

简单实现,

public class MyNotifyClass : INotifyPropertyChanged
{public event PropertyChangedEventHandler PropertyChanged;public void RaisePropertyChanged(string propertyName){PropertyChanged?.Invoke(this, new PropertyChangedEventArgs(propertyName));}
}

改动一下数据源,

public class BindingModeViewModel : MyNotifyClass
{private bool _mark = true;private string _printMessage;public bool Mark{get => _mark;set{if (_mark != value){_mark = value;PrintMessage = $"Mark changed to {_mark}";}}}public string PrintMessage{get => _printMessage;set{_printMessage = value;RaisePropertyChanged(nameof(PrintMessage));}}
}

调整一下界面,

<Grid Background="DeepPink" Width="200" Height="100"><StackPanel><CheckBox Margin="4" Content="Mark" IsChecked="{Binding Mark}" /><TextBlock Margin="4" Text="{Binding PrintMessage}" /></StackPanel>
</Grid>

点击 CheckBox , TextBlock 会动态显示信息。
在这里插入图片描述
CheckBox 只是通过绑定属性,利用属性 Set 方式触发数据源变化。

如果要像按钮 Button 那样,直接通过方法来触发数据源变化,如果操作呢?就要用到命令绑定。

7. 命令绑定

在 WPF 中,命令绑定是 MVVM 模式的核心部分之一,它允许开发者将视图中的事件如按钮点击与 ViewModel 中的命令逻辑相绑定。这样,当用户界面上的按钮被点击时,可以触发 ViewModel 中定义的命令执行相应的操作,而不需要在代码后面编写事件处理函数。

以按钮 Button 控件为例,按钮的 Command 属性类型是一个 ICommand 接口类型,

public ICommand Command
{get => (ICommand) this.GetValue(ButtonBase.CommandProperty);set => this.SetValue(ButtonBase.CommandProperty, (object) value);
}
  public interface ICommand{/// <summary>当出现影响是否应执行该命令的更改时发生。</summary>event EventHandler CanExecuteChanged;/// <summary>定义确定此命令是否可在其当前状态下执行的方法。</summary>/// <param name="parameter">此命令使用的数据。  如果此命令不需要传递数据,则该对象可以设置为 <see langword="null" />。</param>/// <returns>如果可执行此命令,则为 <see langword="true" />;否则为 <see langword="false" />。</returns>bool CanExecute(object parameter);/// <summary>定义在调用此命令时要调用的方法。</summary>/// <param name="parameter">此命令使用的数据。  如果此命令不需要传递数据,则该对象可以设置为 <see langword="null" />。</param>void Execute(object parameter);}

因此我们只要实现一下 ICommand 接口即可使用自己的命令。

例如,

public class MyCommand : ICommand
{private readonly Action<object> _executeAction;private readonly Func<object, bool> _canExecuteFunc;public event EventHandler CanExecuteChanged;public MyCommand(Action<object> executeAction, Func<object, bool> canExecuteFunc = null){_executeAction = executeAction;_canExecuteFunc = canExecuteFunc;}public void Execute(object parameter){_executeAction?.Invoke(parameter);}public bool CanExecute(object parameter){return _canExecuteFunc == null || _canExecuteFunc(parameter);}public void RaiseCanExecute(){CanExecuteChanged?.Invoke(this, EventArgs.Empty);}
}

在数据源增加相应的命令属性,

public class BindingModeViewModel : MyNotifyClass
{private bool _mark = true;private string _printMessage;public bool Mark{get => _mark;set{if (_mark != value){_mark = value;PrintMessage = $"Mark changed to {_mark}";//更新按钮可点击状态PrintCommand.RaiseCanExecute();}}}public string PrintMessage{get => _printMessage;set{_printMessage = value;RaisePropertyChanged(nameof(PrintMessage));}}public MyCommand PrintCommand { get; }public BindingModeViewModel(){PrintCommand = new MyCommand(Print, CanPrint);}private void Print(object obj){PrintMessage = "This is Button Print.";}private bool CanPrint(object arg){return _mark;}
}

界面增加一个按钮,

<Grid Background="DeepPink" Width="200" Height="100"><StackPanel><CheckBox Margin="4" Content="Mark" IsChecked="{Binding Mark}" /><TextBlock Margin="4" Text="{Binding PrintMessage}" /><Button Content="Print" Width="80" Height="32" Command="{Binding PrintCommand}" /></StackPanel>
</Grid>

点击按钮,命令调用成功,
在这里插入图片描述
取消勾选, 按钮变灰,不可执行命令,
在这里插入图片描述

相关文章:

WPF Binding 绑定

绑定是 wpf 开发中的精髓&#xff0c;有绑定才有所谓的数据驱动。 1 . 背景 目前 wpf 界面可视化的控件&#xff0c;继承关系如下&#xff0c; 控件的数据绑定&#xff0c;基本上都要借助于 FrameworkElement 的 DataContext 属性。 只有先设置了控件的 DataContext 属性&…...

算法笔记—前缀和(动态规划)

【模板】前缀和_牛客题霸_牛客网 (nowcoder.com) #include <initializer_list> #include <iostream> #include <vector> using namespace std;int main() {//输入数据int n,q;cin>>n>>q;vector<int> arr;arr.resize(n1);for(int i1;i<…...

将HTML转换为PDF:使用Spire.Doc的详细指南(二)无水印版

目录 引言 一、准备工作 1. 下载Spire.Doc for Java破解版 2. 将JAR包安装到本地Maven (1) 打开命令提示符 (2) 输入安装命令 (3) 在pom.xml中导入依赖 二、实现HTML到PDF的转换 1. 创建Java类 2. 完整代码示例 3. 代码解析 4. 处理图像 5. 性能优化 6. 错误处理…...

V900新功能-电脑不在旁边,通过手机给PLC远程调试网关配置WIFI联网

您使用BDZL-V900时&#xff0c;是否遇到过以下这种问题&#xff1f; 去现场配置WIFI发现没带电脑&#xff0c;无法联网❌ 首次配置WIFI时需使用网线连电脑&#xff0c;不够快捷❌ 而博达智联为解决该类问题&#xff0c;专研了一款网关配网工具&#xff0c;实现用户现场使用手机…...

prober.php探针

raw.githubusercontent.com/kmvan/x-prober/master/dist/prober.php...

esp8266_TFTST7735语音识别UI界面虚拟小助手

文章目录 一 实现思路1 项目简介1.1 项目效果1.2 实现方式 2 项目构成2.1 软硬件环境2.2 完整流程总结&#xff08;重点整合&#xff09;(1) 功能逻辑图(2) 接线(3) 使用esp8266控制TFT屏(4)TFT_espI库配置方法(5) TFT_esp库常用代码详解(6)TFT屏显示图片(7) TFT屏显示汉字(8) …...

【CSS in Depth 2 精译_086】14.3:CSS 剪切路径(clip-path)的用法

当前内容所在位置&#xff08;可进入专栏查看其他译好的章节内容&#xff09; 第四部分 视觉增强技术 ✔️【第 14 章 蒙版、形状与剪切】 ✔️ 14.1 滤镜 14.1.1 滤镜的类型14.1.2 背景滤镜 14.2 蒙版 14.2.1 带渐变效果的蒙版特效14.2.2 基于亮度来定义蒙版14.2.3 其他蒙版属…...

【服务器】MyBatis是如何在java中使用并进行分页的?

MyBatis 是一个支持普通 SQL 查询、存储过程和高级映射的持久层框架。它消除了几乎所有的 JDBC 代码和参数的手动设置以及结果集的检索。MyBatis 可以通过简单的 XML 或注解来配置和映射原始类型、接口和 Java 的 POJO&#xff08;Plain Old Java Objects&#xff0c;普通老式 …...

vue 文本域 展示的内容格式要和填写时保持一致

文本域 展示的内容格式要和填写时保持一致 <el-inputtype"textarea":rows"5"placeholder"请输入内容"v-model"formCredit.point"style"width:1010px;" > </el-input> 样式加个&#xff1a; white-space: pre-w…...

linux-----进程及基本操作

进程的基本概念 定义&#xff1a;在Linux系统中&#xff0c;进程是正在执行的一个程序实例&#xff0c;它是资源分配和调度的基本单位。每个进程都有自己独立的地址空间、数据段、代码段、栈以及一组系统资源&#xff08;如文件描述符、内存等&#xff09;。进程的组成部分&am…...

[Python学习日记-73] 面向对象实战1——答题系统

[Python学习日记-73] 面向对象实战1——答题系统 简介 需求模型——5w1h8c 领域模型 设计模型 实现模型 案例&#xff1a;年会答题系统 简介 在学习完面向对象之后你会发现&#xff0c;你还是不会自己做软件做系统&#xff0c;这是非常正常的&#xff0c;这是因为计算机软…...

Win10将WindowsTerminal设置默认终端并添加到右键(无法使用微软商店)

由于公司内网限制&#xff0c;无法通过微软商店安装 Windows Terminal&#xff0c;本指南提供手动安装和配置新版 Windows Terminal 的步骤&#xff0c;并添加右键菜单快捷方式。 1. 下载新版终端安装包: 访问 Windows Terminal 的 GitHub 发布页面&#xff1a;https://githu…...

AOI外观缺陷检测机

主要功能&#xff1a; 快速检测产品装配缺陷&#xff0c;包括螺丝、元器件、端子排线、二维码、一维条码、识别读码、产品外观 Logo缺陷以及产品标签、字符缺陷检测等产品的缺陷检测。 设备优势&#xff1a;1.采用轻型可移动支架&#xff0c;可以快速对接产线工艺工序&am…...

精读 84页华为BLM战略规划方法论

这篇文档主要介绍了华为的BLM战略规划方法论&#xff0c;该方法论旨在帮助企业制定战略规划&#xff0c;并确保战略规划的可执行性和有效性。以下是该文档的核心知识点和重点需要关注的内容&#xff1a; 战略规划的定义&#xff1a;战略规划是企业依据企业外部环境和企业自身的…...

工业摄像机基于电荷耦合器件的相机

工业摄像机系列产品及其识别技术的详细介绍&#xff1a; 一、工业摄像机概述 工业摄像机是利用光学成像技术获取视觉信息&#xff0c;并通过图像处理算法分析这些信息的设备。它通常具有高图像稳定性、高传输能力和高抗干扰能力等特性&#xff0c;适用于各种复杂的工业环境。 …...

13.罗意文面试

1、工程化与架构设计&#xff08;考察项目管理和架构能力&#xff09; 1.1 你负责的可视化编排项目中&#xff0c;如何设计组件的数据结构来支持"拖拉拽"功能&#xff1f;如何处理组件间的联动关系&#xff1f; // 组件数据结构示例 {components: [{id: comp1,type…...

xxljob window免安装

gitee地址&#xff1a; https://gitee.com/xuxueli0323/xxl-job idea打开 1、配置maven环境 2、修改数据库连接&#xff0c;网页端口 3、修改执行器中连接的网页端口 右侧-xxljob-生命周期-package 生成&#xff1a; D:\xxx\Gitee\xxl-job\xxl-job-admin\target 目录下 x…...

MariaDB 设置 sql_mode=Oracle 和 Oracle 对比验证

功能Oracle语法MariaDB语法Oracle执行结果MariaDB执行结果创建存储过程未使用参数和变量CREATE PROCEDURE p1 ASBEGINNULL;END p1;/ DELIMITER // CREATE PROCEDURE p1()ISBEGINNULL;END // DELIMITER ; 带有参数和变量CREATE PROCEDURE p1(p_input IN NUMBER, p_output OUT NU…...

【AI驱动的数据结构:包装类的艺术与科学】

&#x1f308;个人主页: Aileen_0v0 &#x1f525;热门专栏: 华为鸿蒙系统学习|计算机网络|数据结构与算法 ​&#x1f4ab;个人格言:“没有罗马,那就自己创造罗马~” 文章目录 包装类装箱和拆箱阿里巴巴面试题 包装类 在Java中基本数据类型不是继承来自Object&#xff0c;为了…...

初学stm32 --- PWM输出

目录 STM32 PWM工作过程​编辑 STM32 PWM工作过程&#xff08;通道1为例&#xff09; PWM模式1 & PWM模式2 向上计数配置说明​编辑 STM32 定时器3输出通道引脚 自动重载的预装载寄存器 ​编辑 PWM输出相关库函数 输出比较初始化函数&#xff1a; 设置比较值函数&a…...

Golang 面试经典题:map 的 key 可以是什么类型?哪些不可以?

Golang 面试经典题&#xff1a;map 的 key 可以是什么类型&#xff1f;哪些不可以&#xff1f; 在 Golang 的面试中&#xff0c;map 类型的使用是一个常见的考点&#xff0c;其中对 key 类型的合法性 是一道常被提及的基础却很容易被忽视的问题。本文将带你深入理解 Golang 中…...

日语学习-日语知识点小记-构建基础-JLPT-N4阶段(33):にする

日语学习-日语知识点小记-构建基础-JLPT-N4阶段(33):にする 1、前言(1)情况说明(2)工程师的信仰2、知识点(1) にする1,接续:名词+にする2,接续:疑问词+にする3,(A)は(B)にする。(2)復習:(1)复习句子(2)ために & ように(3)そう(4)にする3、…...

循环冗余码校验CRC码 算法步骤+详细实例计算

通信过程&#xff1a;&#xff08;白话解释&#xff09; 我们将原始待发送的消息称为 M M M&#xff0c;依据发送接收消息双方约定的生成多项式 G ( x ) G(x) G(x)&#xff08;意思就是 G &#xff08; x ) G&#xff08;x) G&#xff08;x) 是已知的&#xff09;&#xff0…...

1.3 VSCode安装与环境配置

进入网址Visual Studio Code - Code Editing. Redefined下载.deb文件&#xff0c;然后打开终端&#xff0c;进入下载文件夹&#xff0c;键入命令 sudo dpkg -i code_1.100.3-1748872405_amd64.deb 在终端键入命令code即启动vscode 需要安装插件列表 1.Chinese简化 2.ros …...

Cinnamon修改面板小工具图标

Cinnamon开始菜单-CSDN博客 设置模块都是做好的&#xff0c;比GNOME简单得多&#xff01; 在 applet.js 里增加 const Settings imports.ui.settings;this.settings new Settings.AppletSettings(this, HTYMenusonichy, instance_id); this.settings.bind(menu-icon, menu…...

TRS收益互换:跨境资本流动的金融创新工具与系统化解决方案

一、TRS收益互换的本质与业务逻辑 &#xff08;一&#xff09;概念解析 TRS&#xff08;Total Return Swap&#xff09;收益互换是一种金融衍生工具&#xff0c;指交易双方约定在未来一定期限内&#xff0c;基于特定资产或指数的表现进行现金流交换的协议。其核心特征包括&am…...

BCS 2025|百度副总裁陈洋:智能体在安全领域的应用实践

6月5日&#xff0c;2025全球数字经济大会数字安全主论坛暨北京网络安全大会在国家会议中心隆重开幕。百度副总裁陈洋受邀出席&#xff0c;并作《智能体在安全领域的应用实践》主题演讲&#xff0c;分享了在智能体在安全领域的突破性实践。他指出&#xff0c;百度通过将安全能力…...

云原生玩法三问:构建自定义开发环境

云原生玩法三问&#xff1a;构建自定义开发环境 引言 临时运维一个古董项目&#xff0c;无文档&#xff0c;无环境&#xff0c;无交接人&#xff0c;俗称三无。 运行设备的环境老&#xff0c;本地环境版本高&#xff0c;ssh不过去。正好最近对 腾讯出品的云原生 cnb 感兴趣&…...

基于Java+MySQL实现(GUI)客户管理系统

客户资料管理系统的设计与实现 第一章 需求分析 1.1 需求总体介绍 本项目为了方便维护客户信息为了方便维护客户信息&#xff0c;对客户进行统一管理&#xff0c;可以把所有客户信息录入系统&#xff0c;进行维护和统计功能。可通过文件的方式保存相关录入数据&#xff0c;对…...

4. TypeScript 类型推断与类型组合

一、类型推断 (一) 什么是类型推断 TypeScript 的类型推断会根据变量、函数返回值、对象和数组的赋值和使用方式&#xff0c;自动确定它们的类型。 这一特性减少了显式类型注解的需要&#xff0c;在保持类型安全的同时简化了代码。通过分析上下文和初始值&#xff0c;TypeSc…...