WPF-绑定

1. 概述

数据绑定是 WPF 中一种强大的机制,用于在数据源和 UI 元素之间建立连接,使得数据的变化能够自动反映在 UI 上,反之亦然。数据绑定简化了 UI 和数据层之间的交互,提高了代码的可维护性和可读性。

2. 绑定类型

WPF 支持多种类型的绑定,主要包括:

  • 单向绑定 (One-Way Binding)
  • 双向绑定 (Two-Way Binding)
  • 单向到源绑定 (One-Way to Source Binding)
  • 一次绑定 (One-Time Binding)
  • 默认绑定
2.1 单向绑定 (One-Way Binding)
  • 描述:数据从数据源流向目标(UI 元素),但不会反向流动。
  • 使用场景:适用于数据源变化需要更新 UI 的情况。
  • 语法:Mode=OneWay
2.2 双向绑定 (Two-Way Binding)
  • 描述:数据可以在数据源和目标之间双向流动。
  • 使用场景:适用于需要双向同步数据的情况,如表单输入。
  • 语法:Mode=TwoWay
2.3 单向到源绑定 (One-Way to Source Binding)
  • 描述:数据从目标流向数据源,但不会反向流动。
  • 使用场景:适用于 UI 元素的变化需要更新数据源的情况。
  • 语法:Mode=OneWayToSource
2.4 一次绑定 (One-Time Binding)
  • 描述:数据从数据源流向目标一次,之后不再更新。
  • 使用场景:适用于初始化时需要设置 UI 元素的值,且不需要后续更新的情况。
  • 语法:Mode=OneTime
2.5 默认绑定
  • 描述:根据目标属性的 DefaultUpdateMode 属性决定绑定模式。
  • 语法:省略 Mode 属性

3. 实现步骤

3.1 创建数据源

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

复制代码
csharp

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));
    }
}
3.2 设置 DataContext

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

复制代码
csharp

public partial class MainWindow : Window
{
    public MainWindow()
    {
        InitializeComponent();
        this.DataContext = new Person { Name = "John Doe" };
    }
}
3.3 创建绑定

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

复制代码
xml

<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>

4. 示例

4.1 单向绑定示例
复制代码
xml

<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">
        <TextBlock Text="{Binding Path=Name, Mode=OneWay}" Width="200"/>
    </StackPanel>
</Window>
4.2 双向绑定示例
复制代码
xml

<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>
4.3 单向到源绑定示例
复制代码
xml

<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=OneWayToSource, UpdateSourceTrigger=PropertyChanged}" Width="200" Margin="0,0,0,10"/>
        <TextBlock Text="Type in the TextBox above" Width="200"/>
    </StackPanel>
</Window>
4.4 一次绑定示例
复制代码
xml

<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">
        <TextBlock Text="{Binding Path=Name, Mode=OneTime}" Width="200"/>
    </StackPanel>
</Window>

5. 高级用法

5.1 转换器 (Converters)

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

复制代码
csharp

using System;
using System.Globalization;
using System.Windows.Data;

public class BoolToVisibilityConverter : IValueConverter
{
    public object Convert(object value, Type targetType, object parameter, CultureInfo culture)
    {
        return (bool)value ? System.Windows.Visibility.Visible : System.Windows.Visibility.Collapsed;
    }

    public object ConvertBack(object value, Type targetType, object parameter, CultureInfo culture)
    {
        throw new NotImplementedException();
    }
}

在 XAML 中使用转换器:

复制代码
xml

<Window x:Class="WpfApp.MainWindow"
        xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
        xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
        xmlns:local="clr-namespace:WpfApp"
        Title="MainWindow" Height="200" Width="300">
    <Window.Resources>
        <local:BoolToVisibilityConverter x:Key="BoolToVisibilityConverter"/>
    </Window.Resources>
    <StackPanel Margin="10">
        <CheckBox x:Name="chkShowText" Content="Show Text"/>
        <TextBlock Text="This text is visible based on checkbox state" 
                   Visibility="{Binding ElementName=chkShowText, Path=IsChecked, Converter={StaticResource BoolToVisibilityConverter}}"/>
    </StackPanel>
</Window>
5.2 多绑定 (MultiBinding)

多绑定允许将多个源绑定到一个目标属性,并使用转换器处理这些源的值。

复制代码
csharp

using System;
using System.Globalization;
using System.Windows.Data;

public class ConcatenateConverter : IMultiValueConverter
{
    public object Convert(object[] values, Type targetType, object parameter, CultureInfo culture)
    {
        if (values == null || values.Length < 2)
            return string.Empty;

        return $"{values[0]} {values[1]}";
    }

    public object[] ConvertBack(object value, Type[] targetTypes, object parameter, CultureInfo culture)
    {
        throw new NotImplementedException();
    }
}

在 XAML 中使用多绑定:

复制代码
xml

<Window x:Class="WpfApp.MainWindow"
        xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
        xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
        xmlns:local="clr-namespace:WpfApp"
        Title="MainWindow" Height="200" Width="300">
    <Window.Resources>
        <local:ConcatenateConverter x:Key="ConcatenateConverter"/>
    </Window.Resources>
    <StackPanel Margin="10">
        <TextBox x:Name="txtFirstName" Width="200" Margin="0,0,0,10"/>
        <TextBox x:Name="txtLastName" Width="200" Margin="0,0,0,10"/>
        <TextBlock>
            <TextBlock.Text>
                <MultiBinding Converter="{StaticResource ConcatenateConverter}">
                    <Binding ElementName="txtFirstName" Path="Text"/>
                    <Binding ElementName="txtLastName" Path="Text"/>
                </MultiBinding>
            </TextBlock.Text>
        </TextBlock>
    </StackPanel>
</Window>
5.3 相对源绑定 (RelativeSource Binding)

相对源绑定允许绑定到相对于当前绑定目标的位置的元素。

复制代码
xml

<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 x:Name="txtInput" Width="200" Margin="0,0,0,10"/>
        <TextBlock Text="{Binding RelativeSource={RelativeSource AncestorType=TextBox}, Path=Text}"/>
    </StackPanel>
</Window>
5.4 元素绑定 (Element Binding)

元素绑定允许绑定到同一窗口或其他容器中的另一个元素。

复制代码
xml

<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 x:Name="txtInput" Width="200" Margin="0,0,0,10"/>
        <TextBlock Text="{Binding ElementName=txtInput, Path=Text}"/>
    </StackPanel>
</Window>

6. 总结

  • 单向绑定:数据从数据源流向目标。
  • 双向绑定:数据在数据源和目标之间双向流动。
  • 单向到源绑定:数据从目标流向数据源。
  • 一次绑定:数据从数据源流向目标一次。
  • 默认绑定:根据目标属性的 DefaultUpdateMode 决定绑定模式。
相关推荐
gregmankiw40 分钟前
C#调用Rust动态链接库DLL的案例
开发语言·rust·c#
阿蒙Amon2 小时前
06. C#入门系列【自定义类型】:从青铜到王者的进阶之路
开发语言·c#
o0向阳而生0o3 小时前
65、.NET 中DllImport的用途
.net·非托管·dllimport
喵叔哟3 小时前
25.【.NET8 实战--孢子记账--从单体到微服务--转向微服务】--单体转微服务--用户服务接口
微服务·架构·.net
钢铁男儿5 小时前
C# 表达式和运算符(表达式和字面量)
开发语言·c#
林鸿群6 小时前
C#子线程更新主线程UI及委托回调使用示例
开发语言·c#
o0向阳而生0o6 小时前
63、.NET 异常处理
c#·.net·异常处理
SteveDraw8 小时前
C++动态链接库封装,供C#/C++ 等编程语言使用——C++动态链接库概述(总)
开发语言·c++·c#·封装·动态链接库
大霸王龙9 小时前
系统模块与功能设计框架
人工智能·wpf
Kookoos9 小时前
性能剖析:在 ABP 框架中集成 MiniProfiler 实现性能可视化诊断
后端·c#·.net·abp vnext·miniprofiler