WPF 绑定 Binding

绑定(Binding)

在 WPF 中,绑定(Binding) 是最核心的概念之一,它允许你将 UI 控件和数据模型之间建立连接,从而实现界面和数据的自动同步。


一、Binding 基本语法

最常见的绑定写法如下:

<TextBlock Text="{Binding Name}" />

这表示将 TextBlockText 属性绑定到当前 DataContext 中的 Name 属性。



二、Binding 的关键组成

{Binding Path=Name, Mode=TwoWay, UpdateSourceTrigger=PropertyChanged}
{Binding Path=属性名, 
         Source=数据源对象, 
         ElementName=元素名, 
         RelativeSource=相对源, 
         Mode=绑定模式, 
         UpdateSourceTrigger=触发时机, 
         Converter=值转换器, 
         ConverterParameter=转换参数}
属性作用
ElementName元素名
Path属性名
Mode绑定模式(见下表)
UpdateSourceTrigger指定何时将值写回数据源(主要用于双向绑定)
Converter转换器

常用绑定模式(Mode)

模式方向说明
OneWay目标 数据源目标(UI)会随着数据源变化自动更新,但反之不会。常用于只读显示。
TwoWay数据源 目标双向绑定,UI 和数据源会互相更新。常用于可编辑控件,如 TextBoxSlider
OneWayToSource目标 数据源OneWay 相反。目标控件的值传给数据源,数据源变化不会影响目标。
OneTime初始化绑定(一次)加载时从数据源获取一次值,之后不再跟踪更新。性能好,但不自动刷新。
Default取决于属性类型WPF 会自动选择模式:大多数属性用 OneWay,如 TextBlock.Text;用户输入控件用 TwoWay,如 TextBox.Text


三、DataContext(绑定的上下文)

方法一:在 XAML 中设置(常用于简单演示或静态数据)

<Window x:Class="WpfApp1.MainWindow"
        xmlns:local="clr-namespace:WpfApp1">
    <Window.DataContext>
        <local:Person Name="张三" />
    </Window.DataContext>

    <Grid>
        <TextBlock Text="{Binding Name}" />
    </Grid>
</Window>

方法二:在代码后端设置(推荐 MVVM 模式)

一般在构造函数中设置 DataContext

public partial class MainWindow : Window
{
    public MainWindow()
    {
        InitializeComponent();
        this.DataContext = new Person { Name = "李四" };
    }
}

方法三:给特定控件设置 DataContext(只影响它自己及其子控件)

<StackPanel>
    <StackPanel.DataContext>
        <local:Person Name="王五" />
    </StackPanel.DataContext>

    <TextBlock Text="{Binding Name}" />
</StackPanel>

方法四:绑定到另一个元素的属性(使用 ElementName)

<StackPanel>
    <Slider x:Name="MySlider" Minimum="0" Maximum="100" Value="50"/>
    <TextBlock Text="{Binding Value, ElementName=MySlider}" />
</StackPanel>

方法五:使用 RelativeSource(绑定到父控件、模板、自己等)

<TextBlock Text="{Binding DataContext.Title, RelativeSource={RelativeSource AncestorType=Window}}" />

这表示从“当前所在的窗口”的 DataContext 中绑定 Title 属性。

用法适用场景
Window.DataContext设置整个窗口的绑定上下文
this.DataContext = ...在代码中更灵活设置绑定对象
ElementName在控件间绑定值(如 Slider → TextBlock)
RelativeSource模板、父控件、自己等特殊结构绑定
局部控件 .DataContext局部作用域绑定,覆盖继承来的上下文


四、绑定示例(单向绑定)

1. 创建数据源:

数据源可以是任何实现了 INotifyPropertyChanged 接口的对象,以便在属性变化时通知绑定系统。

using System.ComponentModel;
 
public class Person : INotifyPropertyChanged
{
    private string name;
    public string Name
    {
        get { return name; }
        set
        {
            if (name != value)
            {
                name = value;
                //通知上下文变化
                OnPropertyChanged(nameof(Name));
            }
        }
    }
 
    public event PropertyChangedEventHandler PropertyChanged;
 
    protected virtual void OnPropertyChanged(string propertyName)
    {
        PropertyChanged?.Invoke(this, new PropertyChangedEventArgs(propertyName));
    }
}

2. 设置 DataContext

在 XAML 或代码中设置 DataContext,将数据源与 UI 关联起来。

//方法1. 在 .CS 代码绑定
public partial class MainWindow : Window
{
    public MainWindow()
    {
        InitializeComponent();
        this.DataContext = new Person { Name = "John Doe" };
    }
}
<!--方法2. 在xaml中设置上下文-->
xmlns:vm="clr-namespace:MVVM_模式.ViewModel"<!--先引用命名空间-->

<!--绑定上下文-->
<Window.DataContext>
  <vm:MainModelViewModel />
</Window.DataContext>


3. 创建绑定

在 XAML 中使用 Binding 标记扩展来创建绑定。

<Window x:Class="WpfApp.MainWindow"
        xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
        xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
        Title="MainWindow" Height="200" Width="300">
  
    <StackPanel Margin="10">
        <TextBox Text="{Binding Path=Name, Mode=TwoWay, UpdateSourceTrigger=PropertyChanged}" Width="200" Margin="0,0,0,10"/>
        <TextBlock Text="{Binding Path=Name}" Width="200"/>
    </StackPanel>
</Window>


五、绑定示例(双向绑定)

这里以 MVVM 模式示例 :

1. Model 类:

通常不需要 实现 INotifyPropertyChanged

  1. 标准做法:

    • Model 层:仅是纯数据对象,不包含 UI 状态逻辑,不实现 INotifyPropertyChanged

    • ViewModel 层:处理通知逻辑,由 ViewModel 来监听 Model 的变化(如果需要),并将其转换为 INotifyPropertyChanged 通知给 View。

    • 优点:

      • Model 更加干净、独立、可复用、可用于非 WPF 场景(如 Web API、数据库等)。

      • ViewModel 保持对 UI 状态的完全控制。

  2. 可以实现 INotifyPropertyChanged 的情况:

    • 你的 Model 是领域模型或服务模型,会被多个地方绑定并直接用于 UI 展示;
    • 或者你希望简化代码逻辑,让 Model 自身具备通知能力;
    • 代价是:
      • 模型耦合了 WPF 通知机制,不再是“纯粹”的数据模型;
      • 可能导致测试或重用变得复杂。
using System.ComponentModel;

public class Student
{
  private int id;
  public int Id { get; set; }

  private string name;
  public string Name { get; set; }
  
}

2. 设置 ViewModel(代码中):

也要实现INotifyPropertyChanged接口

internal class MainModelViewModel:INotifyPropertyChanged
{
    //ObservableCollection<T> 是 .NET 中的一个集合类,位于命名空间 System.Collections.ObjectModel,它的特点是:
    //当集合中的数据发生变化(增、删、清空)时,它会自动通知界面(View)刷新 UI
    public ObservableCollection<Student> Students { get; set; } = new ObservableCollection<Student>()
    {
        new Student(){ Id = 1, Name = "张三" },
        new Student(){ Id = 2, Name = "李四" },
        new Student(){ Id = 3, Name = "王五" },
    };
}

 //实现接口自动生成
  public event PropertyChangedEventHandler PropertyChanged;
  protected void OnPropertyChanged(string propertyName) 
  {
    PropertyChanged?.Invoke(this, new PropertyChangedEventArgs(propertyName));
  }
  • 如果你只是修改集合中某个对象的属性(例如改名字),这个对象本身也要实现INotifyPropertyChanged,才能让界面更新。

  • ObservableCollection 适用于小量数据,对于大数据推荐使用分页等机制。



3. XAML 中绑定控件(双向):

<!--先引用命名空间-->
xmlns:vm="clr-namespace:MVVM_模式.ViewModel"

<!--绑定上下文-->
<Window.DataContext>
  <vm:MainModelViewModel />
</Window.DataContext>

双向绑定的两个关键点:

要素说明
Mode=TwoWay显式启用双向绑定
INotifyPropertyChanged数据源属性变化时通知 UI 更新

补充:UpdateSourceTrigger 说明

触发方式用于
Default一般是失去焦点时更新
PropertyChanged用户每输入一个字符就更新 ViewModel(推荐)
LostFocus控件失去焦点时更新
Explicit必须手动调用 BindingExpression.UpdateSource() 更新数据

转换器 (Converters)

转换器用于在数据绑定过程中转换数据。

单值转换器 / 多值转换器

一、单值转换器

IValueConverter

特点:

  • 一次只处理一个值
  • 最常用
  • 绑定表达式只绑定一个属性
  • 必须实现 IValueConverter接口

接口:

public interface IValueConverter
{
    object Convert(object value, Type targetType, object parameter, CultureInfo culture);
    object ConvertBack(object value, Type targetType, object parameter, CultureInfo culture);
}
示例:bool → Color
public class BoolToBrushConverter : IValueConverter
{
    public object Convert(object value, Type targetType, object parameter, CultureInfo culture)
    {
        return (bool)value ? Brushes.Green : Brushes.Red;
    }

    public object ConvertBack(...) => throw new NotImplementedException();
}

使用:

<Ellipse Fill="{Binding IsOnline, Converter={StaticResource BoolToBrushConverter}}" />



二、多值转换器

IMultiValueConverter

特点:

  • 一次处理多个绑定值
  • 必须配合 <MultiBinding> 使用
  • 比如多个字段决定一个按钮是否启用
  • 必须实现 IMultiValueConverter接口

接口:

public interface IMultiValueConverter
{
    object Convert(object[] values, Type targetType, object parameter, CultureInfo culture);
    object[] ConvertBack(object value, Type[] targetTypes, object parameter, CultureInfo culture);
}
示例:两个 bool → 控件是否可用
public class BothTrueToEnabledConverter : IMultiValueConverter
{
  public object Convert(object[] values, Type targetType, object parameter, CultureInfo culture)
  {
    //如果传进来的绑定值少于 2 个(例如没绑定好、或数据为空),就直接返回 false,避免报错。
    if (values.Length < 2) return false;
    
    //如果两个值都为 true,才返回 true,否则返回 false。
    return (bool)values[0] && (bool)values[1];
  }

  public object[] ConvertBack(...) => throw new NotImplementedException();
}

使用方式:

<Button Content="提交">
    <Button.IsEnabled>
      <!--多值绑定-->
        <MultiBinding Converter="{StaticResource BothTrueToEnabledConverter}">
            <Binding Path="IsNameFilled"/>
            <Binding Path="IsEmailFilled"/>
        </MultiBinding>
    </Button.IsEnabled>
</Button>



怎么用转换器?(完整步骤)

如创建一个单值转换器:

第 1 步:创建一个转换器类

public class BoolToColorConverter : IValueConverter
{
    
  public object Convert(object value, Type targetType, object parameter, CultureInfo culture)
    {
        bool isOnline = (bool)value;
        return isOnline ? Brushes.Green : Brushes.Red;
    }

    public object ConvertBack(object value, Type targetType, object parameter, CultureInfo culture)
    {
        throw new NotImplementedException(); // 通常只需要 Convert
    }
}

各个参数的含义如下:

参数名类型作用说明
valueobject绑定源传入的值。你要转换的“原始数据”,比如 IsOnline 的值(true/false)。
targetTypeType目标属性的类型,比如目标控件的 FillBrush 类型。
parameterobject绑定时额外传入的参数,常用于传递控制逻辑的字符串或数值。
cultureCultureInfo区域信息,通常用于格式化(比如数字、日期等),很少改动。

第 2 步:在 XAML 中声明资源

xmlns:local="clr-namespace:YourApp.Converters" <!--导入命名空间-->

<Window.Resources>
    <local:BoolToColorConverter x:Key="BoolToColor"/>
</Window.Resources>

第 3 步:绑定中使用

<Ellipse Width="20" Height="20"
         Fill="{Binding IsOnline, Converter={StaticResource BoolToColor}}"/>
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值