WPF绑定由简到繁深入笔记

一、什么是绑定(一句话理解)

  1. 最简单的绑定:把 TextBlock 绑定到 TextBox

  2. 绑定的核心组成(SourcePathTarget

  3. 绑定方向(Mode:OneWay / TwoWay / OneTime)

  4. 通知机制(INotifyPropertyChanged 是灵魂)

  5. 绑定到其他元素 / 相对资源(ElementNameRelativeSource

  6. 绑定集合:ListBox / DataGrid 绑定到 ObservableCollection<T>

  7. 值转换器(IValueConverter

WPF 绑定 = 让界面(View)和一个数据对象(ViewModel / Model)自动保持同步,不用写大量 xx.Text = yy 这样的代码。

  • 数据变了 → 界面自动变

  • 界面改了(比如 TextBox 输入) → 数据自动变

二、简单案例:

  • 一个 TextBox 输入名字

  • 一个 TextBlock 实时显示相同内容

cs 复制代码
<StackPanel Margin="20">
    <TextBox x:Name="NameInput" Width="200" Margin="5"/>
    <TextBlock Text="{Binding Text, ElementName=NameInput}" Margin="5"/>
</StackPanel>

效果

你往 TextBox 打字 → TextBlock 实时变化

解释

  • {Binding Text, ElementName=NameInput}

    • TextTextBox 的属性

    • ElementName:告诉绑定去界面上的哪个控件找

✅ 这是最简单的 控件→控件绑定

三、绑定的核心组成

角色 说明 例子
目标(Target) UI 控件属性 TextBlock.Text
源(Source) 数据来源 一个 C# 对象、另一个控件、静态资源
路径(Path) 源对象的具体属性 UserName
模式(Mode) 数据传输方向 TwoWay / OneWay
cs 复制代码
<TextBox Text="{Binding Path=UserName, Mode=TwoWay, UpdateSourceTrigger=PropertyChanged}"/>

四、绑定方向(重要)

Mode 含义 场景
OneWay 数据→界面 只读展示
TwoWay 数据⇄界面 表单编辑
OneTime 只绑一次 静态标签
OneWayToSource 界面→数据 罕见

五、通知机制(INotifyPropertyChanged)

这是 WPF 绑定的灵魂。

场景

你用代码改了数据,界面不更新

👉 因为没有告诉界面"我变了"

错误写法(无通知)

cs 复制代码
public class Student
{
    public string Name { get; set; }
}

正确写法(支持通知)

cs 复制代码
using System.ComponentModel;

public class Student : INotifyPropertyChanged
{
    private string _name;
    public string Name
    {
        get => _name;
        set
        {
            _name = value;
            OnPropertyChanged(nameof(Name));
        }
    }

    public event PropertyChangedEventHandler PropertyChanged;
    protected void OnPropertyChanged(string prop) =>
        PropertyChanged?.Invoke(this, new PropertyChangedEventArgs(prop));
}

界面使用(DataContext 是核心)

cs 复制代码
// 窗口构造函数中
public MainWindow()
{
    InitializeComponent();
    DataContext = new Student { Name = "张三" };
}
XML 复制代码
xml

<TextBox Text="{Binding Name, Mode=TwoWay, UpdateSourceTrigger=PropertyChanged}"/>

✅ 现在 TextBox 输入

✅ C# 里 student.Name = "李四"

👉 界面都会同步

UpdateSourceTrigger=PropertyChanged

效果

你每敲一个字母 → TextBlock 立刻跟着变一个字

数据流向

你按 a → 界面立刻把 a 写回 ViewModel.UserNameTextBlock 收到变化通知 → 显示 a

默认值(LostFocus)→ 失去焦点才更新

UpdateSourceTrigger 比喻
PropertyChanged 微信实时聊天:你每打一个字,对方立刻看到
LostFocus(默认) 发邮件:你写好整封信,点击"发送"后才发出
什么时候更新数据源? 典型场景
PropertyChanged 属性每次变化(每按一个键、每动一下滑块) 实时搜索、实时计算、实时预览
LostFocus(默认) 控件失去焦点(按Tab、点别处) 表单提交、设置页面
Explicit 手动调用 BindingExpression.UpdateSource() 复杂验证、批量保存

六、绑定到其他元素 / 相对资源

1. 绑定到另一个控件(滑块→文字)

XML 复制代码
<Slider x:Name="VolumeSlider" Minimum="0" Maximum="100"/>
<TextBlock Text="{Binding Value, ElementName=VolumeSlider}"/>

2. 绑定到自身窗口属性

XML 复制代码
<TextBlock Text="{Binding Title, RelativeSource={RelativeSource AncestorType=Window}}"/>

3. 绑定到静态资源

XML 复制代码
<Window.Resources>
    <local:Student x:Key="DefaultStudent" Name="王五"/>
</Window.Resources>

<TextBlock Text="{Binding Name, Source={StaticResource DefaultStudent}}"/>

七、绑定集合(最常用)

场景

用户列表显示在 ListBox / DataGrid

增删改自动刷新界面

✅ 必须用 ObservableCollection<T>

cs 复制代码
public class MainViewModel
{
    public ObservableCollection<Student> Students { get; set; }
        = new ObservableCollection<Student>();

    public MainViewModel()
    {
        Students.Add(new Student { Name = "张三" });
        Students.Add(new Student { Name = "李四" });
    }
}

XAML

XML 复制代码
<ListBox ItemsSource="{Binding Students}" DisplayMemberPath="Name"/>
<DataGrid ItemsSource="{Binding Students}" AutoGenerateColumns="True"/>

✅ 增删改都会自动更新界面

八、值转换器(IValueConverter)

场景

  • 性别 0/1 → "男"/"女"

  • 金额 int → "¥100.00"

  • bool → Visibility

示例:bool → 是否显示红字

Converter 代码
cs 复制代码
public class BoolToRedConverter : IValueConverter
{
    public object Convert(object value, Type targetType, object parameter, CultureInfo culture)
    {
        return (bool)value ? "Red" : "Black";
    }

    public object ConvertBack(object value, Type targetType, object parameter, CultureInfo culture)
    {
        throw new NotImplementedException();
    }
}
XAML 使用
XML 复制代码
<Window.Resources>
    <local:BoolToRedConverter x:Key="BoolToRed"/>
</Window.Resources>

<TextBlock Text="危险操作"
           Foreground="{Binding IsDangerous, Converter={StaticResource BoolToRed}}"/>
cs 复制代码
using System;
using System.Windows.Data;
using System.Windows.Media;

public class BoolToRedConverter : IValueConverter
{
    public object Convert(object value, Type targetType, object parameter, System.Globalization.CultureInfo culture)
    {
        // value 就是 Binding 传来的 IsDangerous 的值(true/false)
        bool isDangerous = (bool)value;
        
        if (isDangerous)
            return new SolidColorBrush(Colors.Red);  // 危险 → 红色
        else
            return new SolidColorBrush(Colors.Black); // 安全 → 黑色
    }

    public object ConvertBack(object value, Type targetType, object parameter, System.Globalization.CultureInfo culture)
    {
        throw new NotImplementedException(); // 这个例子不需要反向转换
    }
}
复制代码
<TextBlock Foreground="{Binding IsDangerous, Converter=...}" />
                ↑                ↑
                |                |
            目标属性          源属性(路径)

DataContext 指向的对象

找到 IsDangerous 属性

取出值(true / false)

传给 Converter(BoolToRedConverter)

Converter 返回 Brush(红色/黑色)

赋值给 TextBlock.Foreground

九、常见坑与调试技巧(必看)

🔥 坑1:DataContext 没设置

  • 界面没有任何数据

  • 检查this.DataContext = new XXX()

🔥 坑2:属性是字段

csharp

复制代码
// ❌ 不行
public string Name;

🔥 坑3:集合变了但没刷新

  • List<T> → 改成 ObservableCollection<T>

🔥 坑4:对象内部属性变了界面不变

  • 类必须实现 INotifyPropertyChanged

🔥 坑5:绑定路径写错(大小写)

  • Path 区分大小写

最后总结一句话

WPF 绑定 = 搞清楚三件事:数据源是谁、目标控件是谁、数据变化怎么通知。

你不需要一次记住所有细节,但下面 4 个点是必须反复写才能理解的:

  1. DataContext

  2. INotifyPropertyChanged

  3. ObservableCollection<T>

  4. ModeUpdateSourceTrigger

复制代码
相关推荐
暴躁小师兄数据学院2 分钟前
【AI大数据工程师特训笔记】第14讲:Linux操作系统与shell脚本
大数据·人工智能·笔记
土狗TuGou29 分钟前
SQL内功笔记 · 第8篇:事务的四大特性与隔离级别
数据库·笔记·后端·sql·mysql·oracle
智者知已应修善业1 小时前
【51单片机用T0定时器方式1,实现0.5S的时间间隔实现第一次一个灯亮、第二次二个灯亮,直到全部灯亮,然后重复整个过程】2023-12-29
c++·经验分享·笔记·算法·51单片机
智者知已应修善业2 小时前
【51单片机4位静态数码管显示1234】2023-11-14
c++·经验分享·笔记·算法·51单片机
whyTeaFo2 小时前
MIT6.1810: xv6 book Chapter4: Traps and system calls 笔记
笔记
jimbo_lee2 小时前
yocto 用法(随手笔记,记录以备不时之需)
笔记·yocto
胡图图不糊涂^_^5 小时前
测试用例篇——设计测试用例的方法
笔记·学习·测试用例·判定表法·正交法生成用例测试·等价类·边界值
IT19955 小时前
Dify笔记-知识库创建后设置和召回测试
笔记·dify
飞翔中文网6 小时前
Java学习笔记之抽象类
java·笔记·学习
中屹指纹浏览器7 小时前
2026指纹浏览器行为指纹对抗技术详解:从算法识别到真人模拟全方案
经验分享·笔记