依赖属性


  • 与.Net属性对比:

    • 更高效

    • 支持附加功能

      • 更改通知

      • 属性值继承

创建依赖属性


/// <summary>
/// 只能为依赖对象添加依赖属性
/// </summary>
public class DependencyClass : DependencyObject
{
    /// <summary>
    /// 定义依赖属性
    /// 约定俗成命名规则:属性名+Property
    /// </summary>
    public static readonly DependencyProperty NumberProperty =
        DependencyProperty.Register(//注册依赖属性
            "Number", //属性名
            typeof(int), //属性类型
            typeof(DependencyClass), //拥有该属性的类型
            new FrameworkPropertyMetadata(0, FrameworkPropertyMetadataOptions.AffectsMeasure | FrameworkPropertyMetadataOptions.AffectsRender),//附加属性对象*
            new ValidateValueCallback(DependencyClass.IsZero));//值验证回调*


    /// <summary>
    /// 创建属性封装器,用于像设置普通属性一样设置依赖属性
    /// </summary>
    public int Number
    {
        get => (int)GetValue(NumberProperty);
        set => SetValue(NumberProperty, value);
    }

    /// <summary>
    /// 回调方法
    /// </summary>
    /// <param name="value"></param>
    /// <returns></returns>
    public static bool IsZero(object value)
    {
        return (int) value == 0;
    }
}

*为可选项

共享依赖属性


  • 不同的类可使用DependencyProperty.AddOwner方法共享同一依赖项属性

  • 重用依赖项属性可能导致预期外的结果

    • Eg : 使用样式修改TextBlock.FontFamily属性也会印象Control.FontFamily属性,因为共用一个依赖项属性
TextBlock.FontFamilyProperty = TextElement.FontFamilyProperty.AddOwner(typeof(TextBlock));

附加依赖属性


  • 附加依赖项属性使用DependencyProperty.RegisterAttached方法应用到类(定义依赖属性的类)

    • Eg : Grid的Column和Row附加属性
  • 附加属性需要定义两个静态方法来设置和获取属性值

    • 使用属性包装器中的GetValueSetValue方法

    • 约定俗成的命名规则:GetPropertyName和SetPropertyName

public static readonly DependencyProperty ColumnProperty =
    DependencyProperty.RegisterAttached(
        "Column",
        typeof(int),
        typeof(Grid),
        new FrameworkPropertyMetadata(
            0,
            new PropertyChangedCallback(OnCellAttachedPropertyChanged)),
        new ValidateValueCallback(IsIntValueNotNegative));

public static void SetColumn(UIElement element, int value)
{
    if (element == null)
    {
        throw new ArgumentNullException("element");
    }
    element.SetValue(ColumnProperty, value);
}

public static int GetColumn(UIElement element)
{
    if (element == null)
    {
        throw new ArgumentNullException("element");
    }
    return ((int)element.GetValue(ColumnProperty));
}

元数据 FrameworkPropertyMetadata


  • 标识依赖属性的特征
Name Comment
AffectsArrange、AffectsMeasure、AffectsParentArrange和AffectsParentMeasure 该值表示依赖属性是否会影响布局引擎操作期间的排列和测量过程中如何放置相邻的元素或父元素。
AffectsRender 该值指示依赖属性是否会以某种方式影响元素绘制方式,要求重新绘制元素
BindsTwoWayByDefault 该值指示默认情况下属性是否双向绑定
CoerceValueCallback 该属性提供了一个用于在验证依赖项属性之前尝试“纠正”属性值的回调函数
DefaultUpdateSourceTrigger 该值表示 UpdateSourceTrigger 的默认值。
DefaultValue 该值表示依赖属性的默认值。
Inherits 该值指示依赖属性的值是否可继承
IsAnimationProhibited 该值指示是否应在应用了包含元数据实例的依赖项对象上禁用动画。True为禁用
IsNotDataBindable 该值指示依赖属性是否支持数据绑定。True为禁用
Journal 该值表示该属性是否包含应用程序可以或应该作为日记功能实现的一部分而存储的日记信息。
OverridesInheritanceBehavior 该值指示属性值继承计算是否应跨越元素逻辑树中的某些内容边界。
PropertyChangedCallback 该属性提供了一个用于在依赖项属性值改变后触发的回调函数
SubPropertiesDoNotAffectRender 该值指示依赖属性的子属性是否影响包含对象的重绘。

属性验证回调 ValueCallBack


  • 类型

    • CoerceValueCallBack : 尝试验证并将属性值改为可接受的值

    • ValidateValueCallBack : 接受或者拒绝属性值

  • 触发过程

    1. 激活 CoerceValueCallBack 函数尝试修改属性,或者返回DependencyProperty.UnsetValue表示拒绝修改

    2. 激活 ValidateValueCallBack 函数验证属性值是否合法

    3. 前面两个阶段均成功则触发PropertyChangedCallback函数通知属性值已修改