WPF的依赖与附加属性

WPF的依赖与附加属性 核心关系附加属性 ≈ 特殊的依赖属性在 WPF 中附加属性Attached Property是依赖属性Dependency Property的一种特殊实现—— 所有附加属性都是依赖属性但依赖属性不一定是附加属性。用通俗比喻理解依赖属性「自家的属性」—— 定义在某个类中仅主要供这个类自己使用比如 Button 的 Content 属性、你之前问过的自定义 Count 属性附加属性「共享的属性」—— 定义在类 A 中但可以 “附加” 到任意其他 WPF 元素类 B、C、D上使用比如 Grid 的 Row/Column 属性附加到 Button、TextBox 上用来指定控件在 Grid 中的位置。一、先回顾依赖属性DependencyProperty核心特征属于定义它的类是该类的 “固有属性”基于 WPF 属性系统而非普通 CLR 属性的字段 get/set支持数据绑定、样式、动画、属性继承等核心特性定义时用DependencyProperty.Register()方法。极简示例自定义依赖属性using System.Windows; using System.Windows.Controls; // 自定义按钮自带Count依赖属性自家属性 public class MyCountButton : Button { // 1. 定义依赖属性核心 public static readonly DependencyProperty CountProperty DependencyProperty.Register( Count, // 对外暴露的属性名 typeof(int), // 属性类型 typeof(MyCountButton), // 归属类只能给MyCountButton用 new PropertyMetadata(0) // 元数据默认值0 ); // 2. CLR包装器方便代码调用非必须但推荐 public int Count { get (int)GetValue(CountProperty); set SetValue(CountProperty, value); } }XAML 使用方式!-- Count是MyCountButton自己的属性直接赋值 -- local:MyCountButton Count5 Content计数按钮/二、附加属性Attached Property核心特征归属类和使用类分离比如 Grid 定义了 Row 属性但 Row 是给 Button、TextBox 等 Grid 的子元素用的本质是依赖属性继承了依赖属性的所有特性绑定、样式、元数据等定义时用DependencyProperty.RegisterAttached()方法必须提供静态的SetXxx()和GetXxx()方法WPF 系统会通过这两个方法读写属性值。典型场景布局相关Grid.Row/Column、Canvas.Left/Top、DockPanel.Dock布局容器定义属性给子元素设置布局规则行为扩展Validation.ErrorTemplate验证系统给输入控件附加验证模板自定义扩展给任意控件附加 “提示文本”“是否可拖拽” 等通用属性。完整示例自定义附加属性需求定义一个TooltipHelper类里面包含附加属性TipText可以附加到任意 WPF 控件上自动设置控件的 Tooltip。using System.Windows; // 附加属性的定义类通常为静态类 public static class TooltipHelper { // 1. 定义附加属性核心RegisterAttached public static readonly DependencyProperty TipTextProperty DependencyProperty.RegisterAttached( TipText, // 附加属性名 typeof(string), // 属性类型 typeof(TooltipHelper), // 归属类定义属性的类 // 元数据值变更时自动绑定到控件的Tooltip new PropertyMetadata( string.Empty, // 默认值 OnTipTextChanged // 值变更回调 ) ); // 2. 静态Set方法必须给目标元素设置附加属性值 public static void SetTipText(DependencyObject obj, string value) { obj.SetValue(TipTextProperty, value); } // 3. 静态Get方法必须获取目标元素的附加属性值 public static string GetTipText(DependencyObject obj) { return (string)obj.GetValue(TipTextProperty); } // 4. 属性变更回调自动给控件设置Tooltip private static void OnTipTextChanged(DependencyObject d, DependencyPropertyChangedEventArgs e) { // d是附加了该属性的目标控件比如Button、TextBox if (d is FrameworkElement element) { element.ToolTip e.NewValue.ToString(); // 绑定Tooltip } } }使用方式XAML 代码1. XAML 中使用最常见Window x:ClassWpfApp.MainWindow xmlnshttp://schemas.microsoft.com/winfx/2006/xaml/presentation xmlns:xhttp://schemas.microsoft.com/winfx/2006/xaml xmlns:localclr-namespace:WpfApp Title附加属性示例 Height300 Width400 StackPanel Margin20 !-- 给Button附加TooltipHelper.TipText属性 -- Button Content点击我 local:TooltipHelper.TipText这是自定义提示文本 Width100 Height30 Margin5/ !-- 给TextBox附加TooltipHelper.TipText属性 -- TextBox PlaceholderText输入内容 local:TooltipHelper.TipText请输入手机号 Width200 Height30 Margin5/ !-- 给Grid附加TooltipHelper.TipText任意控件都可以 -- Grid local:TooltipHelper.TipText这是网格容器 Height50 BackgroundLightGray Margin5/ /StackPanel /Window2. 代码中使用附加属性// 给Button设置附加属性值 Button btn new Button(); TooltipHelper.SetTipText(btn, 代码设置的提示); // 获取Button的附加属性值 string tip TooltipHelper.GetTipText(btn);运行效果鼠标悬停在 Button/TextBox/Grid 上时会自动显示对应的提示文本 —— 这就是附加属性的核心价值让一个类定义的属性能给任意 WPF 元素 “附加” 通用功能。三、依赖属性 vs 附加属性核心区别表格维度依赖属性DependencyProperty附加属性Attached Property定义方法Register()RegisterAttached()归属与使用定义类 使用类自家属性定义类 ≠ 使用类共享属性访问方式直接通过 CLR 包装器如btn.Count通过静态 Set/Get 方法如SetTipText核心场景自定义控件的固有属性布局、通用行为扩展跨控件典型示例Button.Content、MyCountButton.CountGrid.Row、Canvas.Left、自定义 TipText总结附加属性是特殊的依赖属性继承了依赖属性的所有核心特性绑定、样式、元数据等依赖属性是 “自家属性”定义类自用附加属性是 “共享属性”定义类给其他控件扩展功能附加属性定义需用RegisterAttached()并提供静态SetXxx/GetXxx方法核心用于布局或跨控件的通用功能扩展。