关注

3.WPF - 依赖属性

WPF - 依赖属性
简述
在 WPF 应用程序中,依赖属性是扩展 CLR 属性的特定类型的属性。它利用了 WPF 属性系统中可用的特定功能。
定义依赖属性的类必须继承自 DependencyObject 类。 XAML 中使用的许多 UI 控件类都派生自 DependencyObject 类,它们支持依赖属性,例如Button 类支持 IsMouseOver 依赖属性。
以下 XAML 代码创建一个带有一些属性的按钮。


<Window x:Class = "WPFDependencyProperty.MainWindow" 
   xmlns = "http://schemas.microsoft.com/winfx/2006/xaml/presentation" 
   xmlns:x = "http://schemas.microsoft.com/winfx/2006/xaml" 
   xmlns:local = "clr-namespace:WPFDependencyProperty"
   Title = "MainWindow" Height = "350" Width = "604"> 
     
   <Grid> 
      <Button  Height = "40" Width = "175" Margin = "10" Content = "Dependency Property"> 
         <Button.Style> 
            <Style TargetType = "{x:Type Button}"> 
               <Style.Triggers> 
                         
                  <Trigger Property = "IsMouseOver" Value = "True"> 
                     <Setter Property = "Foreground" Value = "Red" /> 
                  </Trigger>
                              
               </Style.Triggers>
            </Style> 
         </Button.Style> 
      </Button> 
   </Grid> 
     
</Window> 

XAML 中的 x:Type 标记扩展具有与 C# 中的 typeof() 类似的功能。它用于指定采用对象类型的属性时,例如

using System; 
using System.Collections.Generic; 
using System.Linq; 
using System.Text; 
using System.Threading.Tasks; 
using System.Windows;                // WPF基础命名空间(包含DependencyObject等)
using System.Windows.Controls;       // 用户控件相关类(UserControl)
using System.Windows.Data;           // 数据绑定支持
using System.Windows.Documents;      // 富文本支持
using System.Windows.Input;          // 输入处理(键盘、鼠标)
using System.Windows.Media;          // 图形和渲染(画笔、画刷)
using System.Windows.Media.Imaging;  // 图像处理
using System.Windows.Navigation;     // 导航支持
using System.Windows.Shapes;         // 基本形状(矩形、椭圆等)

namespace WpfApplication3 
{ 
    /// <summary>
    /// 自定义用户控件类,继承自UserControl
    /// 演示依赖属性的实现和使用模式
    /// </summary>
    public partial class UserControl1 : UserControl  // partial类:XAML文件将定义另一部分
    { 
        /// <summary>
        /// 构造函数:初始化控件
        /// </summary>
        public UserControl1() 
        { 
            // 调用InitializeComponent()方法:
            // 1. 加载关联的XAML文件(UserControl1.xaml)
            // 2. 实例化XAML中定义的UI元素
            // 3. 注册事件处理程序
            // 4. 初始化x:Name标识的控件(如tbTest)
            InitializeComponent(); 
        }
              
        /// <summary>
        /// 依赖属性标识符(静态只读字段)
        /// 命名惯例:属性名 + "Property"后缀
        /// </summary>
        public static readonly DependencyProperty SetTextProperty = 
            // 使用DependencyProperty.Register方法注册依赖属性
            DependencyProperty.Register(
                "SetText",                  // 属性名称(字符串)
                typeof(string),             // 属性类型(System.String)
                typeof(UserControl1),       // 所有者类型(声明该属性的类)
                new PropertyMetadata(       // 属性元数据配置
                    "",                     // 默认值(空字符串)
                    new PropertyChangedCallback(OnSetTextChanged) // 属性变更回调方法
                )
            ); 
                    
        /// <summary>
        /// CLR属性包装器(公共接口)
        /// 提供对依赖属性的类型安全访问
        /// </summary>
        public string SetText 
        { 
            // 通过GetValue获取依赖属性当前值
            // DependencyProperty.GetValue()是WPF属性系统的核心方法
            get { return (string)GetValue(SetTextProperty); } 
            
            // 通过SetValue设置依赖属性值
            // 注意:WPF数据绑定会直接调用此方法,绕过setter中的代码
            set { SetValue(SetTextProperty, value); } 
        } 
              
        /// <summary>
        /// 静态属性变更回调方法
        /// 符合DependencyPropertyChangedCallback委托签名
        /// </summary>
        /// <param name="d">发生属性变更的DependencyObject实例(这里是UserControl1实例)</param>
        /// <param name="e">包含新旧值等信息的变更参数</param>
        private static void OnSetTextChanged(
            DependencyObject d,                 // 依赖对象(控件实例)
            DependencyPropertyChangedEventArgs e) // 变更事件参数
        { 
            // 将通用DependencyObject转换为具体类型UserControl1
            // 这是必要的,因为静态方法没有this引用
            UserControl1 userControl = d as UserControl1; 
            
            // 空值检查:确保转换成功
            if (userControl != null)
            {
                // 调用实例方法处理实际变更逻辑
                userControl.OnSetTextChanged(e); 
            }
        } 
              
        /// <summary>
        /// 实例级属性变更处理方法
        /// 执行实际的UI更新逻辑
        /// </summary>
        /// <param name="e">包含新旧值的变更参数</param>
        private void OnSetTextChanged(DependencyPropertyChangedEventArgs e) 
        { 
            // 获取新值并转换为字符串:
            // 1. e.NewValue 是Object类型,包含变更后的值
            // 2. 使用?.操作符避免空引用异常
            // 3. 使用??提供空值回退(空字符串)
            string newValue = e.NewValue?.ToString() ?? string.Empty;
            
            // 更新UI元素:
            // tbTest 是在XAML中定义的TextBlock控件(通过x:Name="tbTest")
            tbTest.Text = newValue; 
        }  
    } 
}

代码执行流程详解:

  1. 初始化阶段

    用户控件加载构造函数InitializeComponentXAML解析器内存new UserControl1()调用加载UserControl1.xaml创建UI元素树返回控件实例用户控件加载构造函数InitializeComponentXAML解析器内存
  2. 属性变更流程

    外部设置属性CLR包装器依赖属性系统静态回调实例方法TextBlock界面SetText = "Hello"SetValue(SetTextProperty, "Hello")OnSetTextChanged(d, e)userControl.OnSetTextChanged(e)tbTest.Text = "Hello"更新显示文本外部设置属性CLR包装器依赖属性系统静态回调实例方法TextBlock界面

关键设计要点解析:

  1. 依赖属性声明

    • DependencyProperty.Register 是WPF属性系统的核心注册方法
    • 元数据中的PropertyChangedCallback指定值变更时的通知机制
    • 静态字段命名SetTextProperty是WPF的标准约定
  2. 回调模式设计

    // 静态方法(框架要求)
    private static void OnSetTextChanged(DependencyObject d, ...)
    {
        // 转换对象类型
        var control = (UserControl1)d;
        
        // 调用实例方法
        control.InstanceOnTextChanged(...);
    }
    
    // 实例方法(业务逻辑)
    private void InstanceOnTextChanged(...)
    {
        // 实际UI更新代码
    }
    

    这种模式是WPF的标准实践,兼顾了框架要求(静态方法)和面向对象设计(实例方法)

  3. XAML依赖

    • tbTest必须在XAML中正确定义:
    <UserControl ...>
        <Grid>
            <TextBlock x:Name="tbTest" />
        </Grid>
    </UserControl>
    
    • 如果名称不匹配,运行时会抛出NullReferenceException
  4. 空值处理

    e.NewValue?.ToString() ?? string.Empty;
    

    使用空条件运算符和空合并运算符确保:

    • e.NewValue为null时不引发异常
    • ToString()返回null时使用空字符串代替

此实现完整展示了WPF自定义控件的标准模式,是理解依赖属性工作机制的经典范例。

转载自CSDN-专业IT技术社区

版权声明:本文为博主原创文章,遵循 CC 4.0 BY-SA 版权协议,转载请附上原文出处链接和本声明。

原文链接:https://blog.csdn.net/weixin_45277917/article/details/151999766

评论

赞0

评论列表

微信小程序
QQ小程序

关于作者

点赞数:0
关注数:0
粉丝:0
文章:0
关注标签:0
加入于:--