- PriorityBinding 用于"按优先级选择多个候选绑定中的第一个可用值"。当更高优先级的绑定后来变得可用时,目标会自动切换到它。
- 典型场景:显示名优先级(DisplayName > UserName > Id)、慢源异步加载(先用本地缓存,后切到远程结果)。
一、核心功能
- 选择策略:按 Bindings 顺序尝试,取第一个成功产生值的绑定。若其值变为不可用(UnsetValue/错误),会回退到下一个可用绑定;更高优先级绑定恢复可用时再切回。
- 属性继承:继承 BindingBase 的能力(StringFormat、TargetNullValue、FallbackValue、Delay)。
- 子绑定能力:每个子 Binding 可拥有自己的 Mode、UpdateSourceTrigger、Converter、Source/ElementName/RelativeSource、IsAsync 等。
- 写回规则:TwoWay 写回时,只写回"当前生效"的子 Binding;若该子绑定是 OneWay 则无法写回。
- 生存期:与普通绑定一致,支持通知更新;不与 MultiBinding 混用,它只选一个,不做合成。
二、使用方式
- 基础:优先显示 DisplayName,不存在则退到 UserName,再退到 Id
xaml
<UserControl x:Class="H.Test.DataGrid.UserControl1"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml">
<StackPanel Margin="12" Orientation="Vertical" Spacing="6">
<TextBlock>
<TextBlock.Text>
<PriorityBinding FallbackValue="(无)" StringFormat="显示名:{0}">
<Binding Path="DisplayName"/>
<Binding Path="UserName"/>
<Binding Path="Id"/>
</PriorityBinding>
</TextBlock.Text>
</TextBlock>
</StackPanel>
</UserControl>
- 与不同源组合:优先取另一个元素的值,其次取 DataContext 的属性
xaml
<UserControl ...>
<StackPanel Margin="12" Orientation="Vertical" Spacing="6">
<TextBox x:Name="NameBox" Text="外部来源"/>
<TextBlock>
<TextBlock.Text>
<PriorityBinding StringFormat="名称:{0}">
<!-- 先尝试来自元素 NameBox 的 Text -->
<Binding ElementName="NameBox" Path="Text"/>
<!-- 再尝试 VM 的属性 -->
<Binding Path="DisplayName"/>
</PriorityBinding>
</TextBlock.Text>
</TextBlock>
</StackPanel>
</UserControl>
- 异步慢源优先:高优先级远程值 IsAsync,加载前使用本地缓存,加载后自动切换
xaml
<UserControl ...>
<StackPanel Margin="12" Orientation="Vertical" Spacing="6">
<TextBlock>
<TextBlock.Text>
<PriorityBinding StringFormat="价格:{0:C2}" FallbackValue="(加载中)">
<!-- 高优先级:远程价格,异步取值 -->
<Binding Path="RemotePrice" IsAsync="True"/>
<!-- 低优先级:本地缓存 -->
<Binding Path="CachedPrice"/>
</PriorityBinding>
</TextBlock.Text>
</TextBlock>
</StackPanel>
</UserControl>
- TwoWay 场景:仅当前生效的子绑定会被写回
xaml
<UserControl ...>
<StackPanel Margin="12" Orientation="Vertical" Spacing="6">
<TextBox>
<TextBox.Text>
<PriorityBinding>
<!-- 若允许写回,请确保子绑定 Mode=TwoWay 且可写 -->
<Binding Path="EditableDisplayName" Mode="TwoWay" UpdateSourceTrigger="PropertyChanged"/>
<Binding Path="EditableUserName" Mode="TwoWay" UpdateSourceTrigger="PropertyChanged"/>
</PriorityBinding>
</TextBox.Text>
</TextBox>
</StackPanel>
</UserControl>
- 简单 ViewModel(示例数据)
csharp
using System;
using System.ComponentModel;
using System.Runtime.CompilerServices;
using System.Windows.Controls;
namespace H.Test.DataGrid
{
public partial class UserControl1 : UserControl
{
public UserControl1()
{
InitializeComponent();
DataContext = new DemoVM
{
DisplayName = null, // 故意置空以触发回退
UserName = "Ada",
Id = 1001,
CachedPrice = 9.99m,
RemotePrice = 0m // 假设后台异步更新该值,触发优先级切换
};
}
}
public sealed class DemoVM : INotifyPropertyChanged
{
private string? _displayName;
private string _userName = "";
private int _id;
private decimal _cachedPrice;
private decimal _remotePrice;
private string _editableDisplayName = "";
private string _editableUserName = "";
public string? DisplayName { get => _displayName; set { _displayName = value; OnPropertyChanged(); } }
public string UserName { get => _userName; set { _userName = value; OnPropertyChanged(); } }
public int Id { get => _id; set { _id = value; OnPropertyChanged(); } }
public decimal CachedPrice { get => _cachedPrice; set { _cachedPrice = value; OnPropertyChanged(); } }
public decimal RemotePrice { get => _remotePrice; set { _remotePrice = value; OnPropertyChanged(); } }
public string EditableDisplayName { get => _editableDisplayName; set { _editableDisplayName = value; OnPropertyChanged(); } }
public string EditableUserName { get => _editableUserName; set { _editableUserName = value; OnPropertyChanged(); } }
public event PropertyChangedEventHandler? PropertyChanged;
private void OnPropertyChanged([CallerMemberName] string? name = null)
=> PropertyChanged?.Invoke(this, new PropertyChangedEventArgs(name));
}
}
三、实践要点与易错
- 写回只针对当前激活的子绑定;如需编辑请确保该子绑定 Mode=TwoWay,且其源可写。
- 与 MultiBinding 区分:PriorityBinding 不拼接值,仅选一个可用值;拼接请用 MultiBinding + StringFormat。
- 可配合 StringFormat/TargetNullValue/FallbackValue 统一包装显示;以 "{" 开头的格式记得用前缀 "{}" 转义。
- 异步慢源优先时,高优先级子绑定可设 IsAsync;当异步完成后,会从低优先级显示切换为高优先级结果。
- 不要把"必须同时生效的多个值"放进 PriorityBinding------它只会选一个。
四、文档链接
- PriorityBinding | Microsoft Learn
- Binding | Microsoft Learn
- BindingBase.StringFormat | Microsoft Learn
- BindingBase.TargetNullValue | Microsoft Learn
- Binding.IsAsync | Microsoft Learn
了解更多
System.Windows.Controls 命名空间 | Microsoft Learn
控件库 - WPF .NET Framework | Microsoft Learn
使用 Visual Studio 创建新应用教程 - WPF .NET | Microsoft Learn
HeBianGu的个人空间-HeBianGu个人主页-哔哩哔哩视频