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

复制代码
相关推荐
LinXunFeng1 天前
Obsidian - 使用 Share Note 分享笔记并自部署
前端·笔记·github
闪闪发亮的小星星6 天前
高斯光以及高斯光公式解释
笔记
cqbzcsq6 天前
CellFlow虚拟细胞论文阅读
论文阅读·人工智能·笔记·学习·生物信息
阿米亚波6 天前
【Windows】QEMU 启动 openEuler aarch64/arm64 架构系统 + 离线软件源
linux·windows·经验分享·笔记·架构·arm
自传.6 天前
尚硅谷 Vibe Coding|第三章(1) Claude Code深度使用与进阶技巧 学习笔记
笔记·学习·尚硅谷·vibecoding
.千余6 天前
【C++】模板进阶全解:非类型参数|全特化|偏特化|分离编译完全指南
开发语言·c++·笔记·学习·其他
自传.6 天前
尚硅谷 Vibe Coding|第二章 AI编程工具生态 学习笔记
笔记·学习·ai编程·尚硅谷·vibe coding
秋波。未央6 天前
Java Agent 开发 · Day 1 学习笔记(含作业完整标准答案)
java·笔记·学习
中屹指纹浏览器6 天前
2026指纹浏览器字体指纹、字体渲染偏差检测与全维度虚拟字体池搭建方案
经验分享·笔记