【笔记】在WPF中PriorityBinding的详细介绍

  • PriorityBinding 用于"按优先级选择多个候选绑定中的第一个可用值"。当更高优先级的绑定后来变得可用时,目标会自动切换到它。
  • 典型场景:显示名优先级(DisplayName > UserName > Id)、慢源异步加载(先用本地缓存,后切到远程结果)。

一、核心功能

  • 选择策略:按 Bindings 顺序尝试,取第一个成功产生值的绑定。若其值变为不可用(UnsetValue/错误),会回退到下一个可用绑定;更高优先级绑定恢复可用时再切回。
  • 属性继承:继承 BindingBase 的能力(StringFormat、TargetNullValue、FallbackValue、Delay)。
  • 子绑定能力:每个子 Binding 可拥有自己的 Mode、UpdateSourceTrigger、Converter、Source/ElementName/RelativeSource、IsAsync 等。
  • 写回规则:TwoWay 写回时,只写回"当前生效"的子 Binding;若该子绑定是 OneWay 则无法写回。
  • 生存期:与普通绑定一致,支持通知更新;不与 MultiBinding 混用,它只选一个,不做合成。

二、使用方式

  1. 基础:优先显示 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>
  1. 与不同源组合:优先取另一个元素的值,其次取 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>
  1. 异步慢源优先:高优先级远程值 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>
  1. 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>
  1. 简单 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------它只会选一个。

四、文档链接

了解更多

System.Windows.Controls 命名空间 | Microsoft Learn

控件库 - WPF .NET Framework | Microsoft Learn

WPF 介绍 | Microsoft Learn

使用 Visual Studio 创建新应用教程 - WPF .NET | Microsoft Learn

https://github.com/HeBianGu

HeBianGu的个人空间-HeBianGu个人主页-哔哩哔哩视频

GitHub - HeBianGu/WPF-Control: WPF轻量控件和皮肤库

GitHub - HeBianGu/WPF-ControlBase: Wpf封装的自定义控件资源库

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