WPF Binding 绑定 超详细详解

WPF Binding(数据绑定) 是 MVVM 模式的核心,也是 WPF 最强大的功能之一。它的作用是:把 UI 控件的属性 和 数据源(变量 / 对象)自动关联,一方变化,另一方自动同步,不用手动写代码赋值。

我会用最通俗、最完整、可直接上手的方式给你讲透,包含:原理、语法、模式、转换器、通知、命令、常见问题。


一、Binding 到底是什么?

一句话:Binding = 桥梁 连接 目标(Target:UI 控件属性) ←→ 源(Source:后台数据)

例如:TextBox.Text ← Binding → string Name

你改界面,后台自动变;你改后台,界面自动变。


二、Binding 四大核心组成

任何一个绑定都必须包含这 4 部分:

  1. Binding Target(绑定目标) 必须是 **依赖属性(Dependency Property)**如:Text、Width、IsChecked、ItemsSource、Visibility 等

  2. **Binding Source(绑定源)**可以是:普通变量、类实例、集合、父控件、自身、资源

  3. Binding Path(绑定路径) 要绑定源的哪个属性

  4. **Binding Mode(绑定模式)**数据流向:单向 / 双向 / 只读一次等


三、最基础的绑定语法(XAML)

1. 标准写法

复制代码
<TextBox Text="{Binding 路径, Mode=模式, ...}" />

单向绑定

复制代码
<CheckBox x:Name="chb_inspectAll" Margin="20,0,0,0" Content="inspect all" IsChecked="{Binding SelectRecipe.IsFullInspect, Mode=OneWay}" />

2. 最简单示例

复制代码
<TextBox Text="{Binding UserName}" />

表示:Text 属性绑定到当前数据源的 UserName 属性。


四、绑定模式(Binding Mode)必考 / 必用

这是 WPF 面试高频题,也是开发必须懂的。

模式 说明 常用控件
TwoWay(默认) 双向同步:UI 变→数据源变,数据源变→UI 变 TextBox、CheckBox
OneWay 单向:数据源变→UI 变 TextBlock、ProgressBar
OneWayToSource 反向:UI 变→数据源变 极少用
OneTime 只初始化一次,之后不同步 一次性显示数据
Default 根据控件自动决定 文本框双向,文本块单向

最常用:TwoWay / OneWay


五、数据源来源(Source)6 种最常用写法

1. 绑定到自身(RelativeSource Self)

控件自己的属性绑定给自己的另一个属性:

复制代码
<Width="{Binding ActualHeight, RelativeSource={RelativeSource Self}}" />

2. 绑定到父控件(AncestorType)

复制代码
Text="{Binding DataContext.Title, RelativeSource={RelativeSource AncestorType=Window}}"

3. 绑定到元素名(ElementName)

复制代码
<TextBox x:Name="input" />
<TextBlock Text="{Binding Text, ElementName=input}" />

4. 绑定到静态资源(StaticResource)

复制代码
Text="{Binding Name, Source={StaticResource MyViewModel}}"

5. 绑定到静态属性(x:Static)

复制代码
Text="{Binding Source={x:Static sys:DateTime.Now}}"

6. 绑定到 DataContext(最常用!MVVM 标配)

复制代码
Text="{Binding UserName}"

DataContext 是传递性的,子控件自动继承父控件数据源。


六、必须实现:数据源变化通知 INotifyPropertyChanged

如果不实现这个接口,数据源变了,UI 不会自动更新!

这是 MVVM 最基础的基类:

复制代码
using System.ComponentModel;
using System.Runtime.CompilerServices;

public class ViewModelBase : INotifyPropertyChanged
{
    public event PropertyChangedEventHandler PropertyChanged;

    protected void OnPropertyChanged([CallerMemberName] string propertyName = null)
    {
        PropertyChanged?.Invoke(this, new PropertyChangedEventArgs(propertyName));
    }

    protected bool SetProperty<T>(ref T field, T value, [CallerMemberName] string propertyName = null)
    {
        if (EqualityComparer<T>.Default.Equals(field, value)) return false;
        field = value;
        OnPropertyChanged(propertyName);
        return true;
    }
}

使用:

复制代码
public class MainViewModel : ViewModelBase
{
    private string _userName;
    public string UserName
    {
        get => _userName;
        set => SetProperty(ref _userName, value);
    }
}

七、集合绑定:ObservableCollection

普通 List<T> 增删数据 UI 不更新,必须用:

复制代码
public ObservableCollection<string> Items { get; set; } = new ObservableCollection<string>();

八、值转换器(IValueConverter)

当数据源类型和 UI 属性类型不匹配时使用,例如:

  • bool ↔ Visibility
  • string ↔ 颜色
  • 数字 ↔ 格式化文本

示例:Bool 转 Visibility

复制代码
public class BoolToVisibilityConverter : IValueConverter
{
    public object Convert(object value, ...)
    {
        return (bool)value ? Visibility.Visible : Visibility.Collapsed;
    }

    public object ConvertBack(object value, ...)
    {
        return (Visibility)value == Visibility.Visible;
    }
}

使用:

复制代码
<Button Visibility="{Binding IsShow, Converter={StaticResource BoolToVis}}" />

九、绑定校验(ValidationRules)

输入不符合规则时显示红框并提示:

复制代码
<TextBox>
    <TextBox.Text>
        <Binding Path="Age">
            <Binding.ValidationRules>
                <ExceptionValidationRule/>
            </Binding.ValidationRules>
        </Binding>
    </TextBox.Text>
</TextBox>

十、字符串格式化(StringFormat)

复制代码
Text="{Binding Price, StringFormat={}{0:C}}"  <!-- 货币格式 -->
Text="{Binding Date, StringFormat=yyyy-MM-dd}"
Text="{Binding Name, StringFormat=欢迎, {0}}"

十一、常用高级特性

1. FallBackValue

绑定失败时显示的默认值

复制代码
Text="{Binding Age, FallbackValue=未知}"

2. TargetNullValue

数据源为 null 时显示的值

复制代码
Text="{Binding Description, TargetNullValue=暂无描述}"

3. UpdateSourceTrigger

什么时候把 UI 的值同步回数据源:

  • PropertyChanged:输入一个字符同步一次

  • LostFocus:失去焦点同步

  • Explicit:手动调用 UpdateSource ()

    Text="{Binding Name, UpdateSourceTrigger=PropertyChanged}"


十二、MVVM 标准完整示例(可直接复制运行)

1. MainWindow.xaml

复制代码
<Window x:Class="WpfApp.MainWindow"
        xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
        xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
        Title="Binding Demo" Height="300" Width="500">
    <StackPanel Margin="20">
        <TextBox Text="{Binding UserName, Mode=TwoWay}" FontSize="20"/>
        <TextBlock Text="{Binding UserName}" FontSize="20" Margin="0 10"/>
        <Button Content="测试修改" Click="Button_Click"/>
    </StackPanel>
</Window>

2. MainWindow.xaml.cs

复制代码
public MainWindow()
{
    InitializeComponent();
    DataContext = new MainViewModel(); // 设置数据源
}

private void Button_Click(object sender, RoutedEventArgs e)
{
    var vm = DataContext as MainViewModel;
    vm.UserName = "来自后台修改:" + DateTime.Now.Second;
}

3. MainViewModel.cs

复制代码
public class MainViewModel : ViewModelBase
{
    private string _userName = "初始值";
    public string UserName
    {
        get => _userName;
        set => SetProperty(ref _userName, value);
    }
}

运行后你会发现:

  • 输入框修改 → 文本块自动同步
  • 点击按钮后台修改 → 输入框和文本块都自动变

这就是 Binding 的魔力!


总结(最重要的 6 条)

  1. Binding = UI ↔ 数据 自动同步桥梁
  2. 目标必须是依赖属性
  3. 源必须实现 INotifyPropertyChanged 才能通知更新
  4. 集合必须用 ObservableCollection<T>
  5. 常用模式:TwoWay / OneWay
  6. 类型不匹配用 IValueConverter 转换器
相关推荐
未来之窗软件服务8 小时前
C# 截图源码支持自动保存-东方仙盟
c#·仙盟创梦ide·东方仙盟·电脑工具
UIU11420 小时前
-7 / 2 在 C 里是 -3,在 Python 里是 -4,谁算错了?
c++·学习·c#
wflynn1 天前
GitHub 今日推荐|REDox:64 位 token 表示结构化数据,内存占用降 70% 支持多格式互转
开源·c#·github
驰骋工作流1 天前
C#/.NET 开源BPM工作流引擎6大常用对比选型分析驰骋BPM驰骋低代码低代码工作流引擎
开源·c#·.net
en.en..1 天前
C语言 fp与fd 区别详解
c#
淡海水2 天前
02-02-原理篇-分代GC
算法·unity·c#·游戏引擎·.net·gc
BD_Marathon2 天前
多轮对话聊天机器人
开发语言·机器人·c#
czhc11400756632 天前
设备标定页防呆为何失效:草稿与真值的错位
c#
周杰伦fans2 天前
轻量模型高并发推理优化技巧
开发语言·人工智能·c#
周杰伦fans2 天前
C#对话摘要降低Token消耗
人工智能·后端·c#