C# 实施登记和注册

C# 实施登记和注册,c#,.net,wpf,C#,.net,Wpf,我将讨论常规依赖属性和附加属性之间的区别 使用ILSpy,我了解了Register和RegisterAttached是如何实现的 注册: // System.Windows.DependencyProperty /// <summary>Registers a dependency property with the specified property name, property type, owner type, property metadata, and a value v

我将讨论常规依赖属性和附加属性之间的区别

使用ILSpy,我了解了Register和RegisterAttached是如何实现的

注册:

// System.Windows.DependencyProperty
/// <summary>Registers a dependency property with the specified property name, property type, owner type, property metadata, and a value validation callback for the property. </summary>
/// <returns>A dependency property identifier that should be used to set the value of a public static readonly field in your class. That identifier is then used to reference the dependency property later, for operations such as setting its value programmatically or obtaining metadata.</returns>
/// <param name="name">The name of the dependency property to register.</param>
/// <param name="propertyType">The type of the property.</param>
/// <param name="ownerType">The owner type that is registering the dependency property.</param>
/// <param name="typeMetadata">Property metadata for the dependency property.</param>
/// <param name="validateValueCallback">A reference to a callback that should perform any custom validation of the dependency property value beyond typical type validation.</param>
public static DependencyProperty Register(string name, Type propertyType, Type ownerType, PropertyMetadata typeMetadata, ValidateValueCallback validateValueCallback)
{
    DependencyProperty.RegisterParameterValidation(name, propertyType, ownerType);
    PropertyMetadata defaultMetadata = null;
    if (typeMetadata != null && typeMetadata.DefaultValueWasSet())
    {
        defaultMetadata = new PropertyMetadata(typeMetadata.DefaultValue);
    }
    DependencyProperty dependencyProperty = DependencyProperty.RegisterCommon(name, propertyType, ownerType, defaultMetadata, validateValueCallback);
    if (typeMetadata != null)
    {
        dependencyProperty.OverrideMetadata(ownerType, typeMetadata);
    }
    return dependencyProperty;
}
// System.Windows.DependencyProperty
/// <summary>Registers an attached property with the specified property type, owner type, property metadata, and value validation callback for the property. </summary>
/// <returns>A dependency property identifier that should be used to set the value of a public static readonly field in your class. That identifier is then used to reference the dependency property later, for operations such as setting its value programmatically or obtaining metadata.</returns>
/// <param name="name">The name of the dependency property to register.</param>
/// <param name="propertyType">The type of the property.</param>
/// <param name="ownerType">The owner type that is registering the dependency property.</param>
/// <param name="defaultMetadata">Property metadata for the dependency property. This can include the default value as well as other characteristics.</param>
/// <param name="validateValueCallback">A reference to a callback that should perform any custom validation of the dependency property value beyond typical type validation.</param>
public static DependencyProperty RegisterAttached(string name, Type propertyType, Type ownerType, PropertyMetadata defaultMetadata, ValidateValueCallback validateValueCallback)
{
    DependencyProperty.RegisterParameterValidation(name, propertyType, ownerType);
    return DependencyProperty.RegisterCommon(name, propertyType, ownerType, defaultMetadata, validateValueCallback);
}
//System.Windows.dependencProperty
///使用指定的属性名称、属性类型、所有者类型、属性元数据和属性的值验证回调注册依赖项属性。
///应用于设置类中公共静态只读字段值的依赖项属性标识符。然后,该标识符用于以后引用依赖项属性,以用于以编程方式设置其值或获取元数据等操作。
///要注册的依赖项属性的名称。
///属性的类型。
///正在注册依赖项属性的所有者类型。
///依赖项属性的属性元数据。
///对回调的引用,该回调应执行除典型类型验证之外的依赖项属性值的任何自定义验证。
公共静态从属属性寄存器(字符串名称、类型propertyType、类型ownerType、属性元数据类型、ValidateValueCallback ValidateValueCallback)
{
DependencyProperty.RegisterParameterValidation(名称、属性类型、所有者类型);
PropertyMetadata defaultMetadata=null;
if(typeMetadata!=null&&typeMetadata.DefaultValueWasSet())
{
defaultMetadata=新的PropertyMetadata(typeMetadata.DefaultValue);
}
DependencyProperty DependencyProperty=DependencyProperty.RegisterCommon(名称、属性类型、所有者类型、默认元数据、validateValueCallback);
if(typeMetadata!=null)
{
dependencyProperty.OverrideMetadata(ownerType,typeMetadata);
}
归还家属;
}
已注册:

// System.Windows.DependencyProperty
/// <summary>Registers a dependency property with the specified property name, property type, owner type, property metadata, and a value validation callback for the property. </summary>
/// <returns>A dependency property identifier that should be used to set the value of a public static readonly field in your class. That identifier is then used to reference the dependency property later, for operations such as setting its value programmatically or obtaining metadata.</returns>
/// <param name="name">The name of the dependency property to register.</param>
/// <param name="propertyType">The type of the property.</param>
/// <param name="ownerType">The owner type that is registering the dependency property.</param>
/// <param name="typeMetadata">Property metadata for the dependency property.</param>
/// <param name="validateValueCallback">A reference to a callback that should perform any custom validation of the dependency property value beyond typical type validation.</param>
public static DependencyProperty Register(string name, Type propertyType, Type ownerType, PropertyMetadata typeMetadata, ValidateValueCallback validateValueCallback)
{
    DependencyProperty.RegisterParameterValidation(name, propertyType, ownerType);
    PropertyMetadata defaultMetadata = null;
    if (typeMetadata != null && typeMetadata.DefaultValueWasSet())
    {
        defaultMetadata = new PropertyMetadata(typeMetadata.DefaultValue);
    }
    DependencyProperty dependencyProperty = DependencyProperty.RegisterCommon(name, propertyType, ownerType, defaultMetadata, validateValueCallback);
    if (typeMetadata != null)
    {
        dependencyProperty.OverrideMetadata(ownerType, typeMetadata);
    }
    return dependencyProperty;
}
// System.Windows.DependencyProperty
/// <summary>Registers an attached property with the specified property type, owner type, property metadata, and value validation callback for the property. </summary>
/// <returns>A dependency property identifier that should be used to set the value of a public static readonly field in your class. That identifier is then used to reference the dependency property later, for operations such as setting its value programmatically or obtaining metadata.</returns>
/// <param name="name">The name of the dependency property to register.</param>
/// <param name="propertyType">The type of the property.</param>
/// <param name="ownerType">The owner type that is registering the dependency property.</param>
/// <param name="defaultMetadata">Property metadata for the dependency property. This can include the default value as well as other characteristics.</param>
/// <param name="validateValueCallback">A reference to a callback that should perform any custom validation of the dependency property value beyond typical type validation.</param>
public static DependencyProperty RegisterAttached(string name, Type propertyType, Type ownerType, PropertyMetadata defaultMetadata, ValidateValueCallback validateValueCallback)
{
    DependencyProperty.RegisterParameterValidation(name, propertyType, ownerType);
    return DependencyProperty.RegisterCommon(name, propertyType, ownerType, defaultMetadata, validateValueCallback);
}
//System.Windows.dependencProperty
///使用指定的属性类型、所有者类型、属性元数据和属性的值验证回调注册附加属性。
///应用于设置类中公共静态只读字段值的依赖项属性标识符。然后,该标识符用于以后引用依赖项属性,以用于以编程方式设置其值或获取元数据等操作。
///要注册的依赖项属性的名称。
///属性的类型。
///正在注册依赖项属性的所有者类型。
///依赖项属性的属性元数据。这可以包括默认值以及其他特征。
///对回调的引用,该回调应执行除典型类型验证之外的依赖项属性值的任何自定义验证。
public static DependencyProperty RegisterAttached(字符串名称、类型propertyType、类型ownerType、属性元数据defaultMetadata、ValidateValueCallback ValidateValueCallback)
{
DependencyProperty.RegisterParameterValidation(名称、属性类型、所有者类型);
返回DependencyProperty.RegisterCommon(名称、propertyType、ownerType、defaultMetadata、validateValueCallback);
}
看起来唯一的区别是如何处理
PropertyMetaData
。Register使用传入的
typeMetaData
参数具有一些额外的逻辑,而RegisterAttached只传递
PropertyMetaData
。然后这两种方法都调用
RegisterCommon

在实现附加属性时,这是唯一的区别吗?我查看了
DependencyObject
上的Set/GetValue方法。它们非常复杂(因此我很容易就错过了一些可以解释事情的关键代码位),但我找不到任何会导致根据Register或RegisterAttached的操作采取不同代码路径的内容

问题:
有人能给我解释一下我上面描述的Register和RegisterAttached之间的区别是什么,以及它如何允许附加属性被用作可在任何对象上设置的全局属性类型?可能实际工作是在
DependencyObject

TLDR上的Set/GetValue方法中完成的:您在代码示例中看到的差异实际上是“附加的”和常规依赖属性之间的唯一区别,在运行代码后,WPF将它们视为相同的对象,不存在以下概念:“attached”属性(比如一些标志
dependencProperty.IsAttached
或类似的东西)

您是对的,“附加”属性和常规依赖属性之间的区别只是元数据处理

首先,完全可以使用常规属性作为附加属性。例如,假设我们有以下属性(注意,在某种意义上它不是“附加的”
RegisterAttached
未使用):

假设我们有如下
TextBlock

<TextBlock x:Name="tb" local:TestProperties.Test="True" />
请注意,这些
GetTest
SetTest
也不是必需的。它们只需要能够从xaml获取\set“attached”属性值就可以了。就您所看到的常规属性和“attached”属性完全相同而言,没有任何区别

当我们开始传递元数据时-尽管存在一些差异。当您注册附加属性时,您传递的元数据将是默认元数据,并将应用于所有类型

public class TestProperties {
    public static readonly DependencyProperty TestProperty = DependencyProperty.RegisterAttached(
        "Test",
        typeof(Boolean),
        typeof(TestProperties),
        new PropertyMetadata(true, OnTestChanged)
    );

    private static void OnTestChanged(DependencyObject d, DependencyPropertyChangedEventArgs e) {

    }

    public static void SetTest(UIElement element, Boolean value) {
        element.SetValue(TestProperty, value);
    }

    public static Boolean GetTest(UIElement element) {
        return (Boolean) element.GetValue(TestProperty);
    }
}
如果我们现在这样做:

var meta = TestProperties.TestProperty.GetMetadata(typeof(TextBlock));
// or any other type
我们将看到,任何类型的元数据都是您传递的默认元数据,带有回调和其他内容。例如,这意味着,只要任何类型的附加属性的值发生更改,就会调用您的值更改回调(如上面示例中的
TextBlock

当我们使用常规
register
向元数据注册属性时,它的行为不同:

PropertyMetadata defaultMetadata = null;
if (typeMetadata != null && typeMetadata.DefaultValueWasSet())
{
    defaultMetadata = new PropertyMetadata(typeMetadata.DefaultValue);
}
DependencyProperty dependencyProperty = DependencyProperty.RegisterCommon(name, propertyType, ownerType, defaultMetadata, validateValueCallback);
首先,它复制默认值(如果有),并仅使用默认值创建新元数据
if (typeMetadata != null)
{
    dependencyProperty.OverrideMetadata(ownerType, typeMetadata);
}
public class TestProperties : DependencyObject { // must inherit dependency object
    public static readonly DependencyProperty TestProperty = DependencyProperty.Register(
        "Test",
        typeof(Boolean),
        typeof(TestProperties),
        new PropertyMetadata(true, OnTestChanged)
    );

    private static void OnTestChanged(DependencyObject d, DependencyPropertyChangedEventArgs e) {
        // this will be called ONLY when we do something like 
        // var prop = new TestProperties();
        // prop.SetValue(TestProperty, true);
        // but will NOT be called when we set value for TextBlock
    }

    public static void SetTest(UIElement element, Boolean value) {
        element.SetValue(TestProperty, value);
    }

    public static Boolean GetTest(UIElement element) {
        return (Boolean) element.GetValue(TestProperty);
    }
}
static TestProperties() {
    TestProperties.TestProperty.OverrideMetadata(typeof(TextBlock), new PropertyMetadata(OnTestChanged));
}