【问题标题】:Dependency Property mechanism [duplicate]依赖属性机制
【发布时间】:2016-07-12 14:40:07
【问题描述】:

依赖属性本质上是静态的,所以如果我创建一个名为“IsGrayProperty”的布尔类型自定义依赖属性,并在两个按钮上实现它。 然后,如果我在 btn1 中设置值,为什么它不应该反映在 btn2 中,因为依赖属性是静态的,它们是 .net 包装器属性“IsGray”

【问题讨论】:

  • 因为 btn2 没有引用 btn1 的属性。

标签: c# wpf data-binding wpf-controls


【解决方案1】:

名为IsGrayProperty 的静态只读DependencyProperty 是一个标识符——可以说是一个键值。它还包含有关该属性的元数据。它不是实际财产本身。每个DependencyObject 实例在内部存储自己的DependencyProperty 值。

依赖属性在语义上与常规实例属性非常相似,但它们具有额外的功能,可以让它们做常规实例属性不能做的事情(例如,您可以在运行时更改它们的元数据,与常规属性上的Attributes 不同,您可以创建附加属性)。这就是它们存在的原因。

例如,TextBlock.Text 是一个依赖属性。

//
// Summary:
//     Identifies the System.Windows.Controls.TextBlock.Text dependency property.
//
// Returns:
//     The identifier of the System.Windows.Controls.TextBlock.Text dependency property.
[CommonDependencyProperty]
public static readonly DependencyProperty TextProperty;

它也有一个“常规属性”包装器:

//
// Summary:
//     Gets or sets the text contents of a System.Windows.Controls.TextBlock.
//
// Returns:
//     The text contents of this System.Windows.Controls.TextBlock. Note that all
//     non-text content is stripped out, resulting in a plain text representation
//     of the System.Windows.Controls.TextBlock contents. The default is System.String.Empty.
[Localizability(LocalizationCategory.Text)]
public string Text { get; set; }

当您设置一个TextBlockText 时,其他所有TextBlock 是否共享相同的文本?不,当然不。如果他们这样做了,依赖属性将完全没用。

GetValueDependencyProperty 参数告诉DependencyObject 从依赖对象自己的内部属性值存储中检索哪个值;如果该值存储在DependencyProperty 本身中,您将查询DependencyProperty不是DependencyObject

public void ForExample(TextBlock tb)
{
    var oldtext = tb.GetValue(TextBlock.TextProperty) as String;

    tb.SetValue(TextBlock.TextProperty, "Test value");
}

如果TextBlock.TextProperty 只有一个全局值,并且它存储在TextBlock.TextProperty,那么我们到底为什么要在@987654344 的某个随机实例上调用GetValue()SetValue() @?为什么要让一个特定的TextBlock 实例参与其中?

相反,我们会调用TextBlock.TextProperty.SetValue()

这就像一个字典:

var d1 = new Dictionary<String, Object>();
var d2 = new Dictionary<String, Object>();
var keyValue = "Foo";

d1.Add(keyValue, 32);

Console.WriteLine( d2[keyValue] );

您对d2[keyValue] 有什么期望?你会期望什么都没有,因为你从来没有给d2 一个keyValue 的值。 d1.Add("Foo",32) 不将整数 32 存储在字符串 "Foo" 中。它将它存储在字典中。

每个字典都存储自己的键值。每个DependencyObject 都存储自己的属性值。在内部,它可能将它们存储在 in Dictionary;为什么不?如果 .NET 团队可以编写比Dictionary 更有效的存储键/值对的方法,他们会称之为Dictionary

当您对语言或框架功能的含义有所了解时,请始终问自己:“如果我的想法是正确的,那么该功能会完全无用还是会带来巨大的危害?”如果该问题的答案是“是”,那么您对该功能的含义猜错了。这是 100% 保证的,因为语言和框架的设计者和实现者不会习惯性地浪费几个月的时间来设计完全无用的功能 (classes in Perl 5 come close, though)。

【讨论】:

  • 谢谢 Ed,是的,你是对的,但没有了解静态属性如何为不同的控件具有不同的值,尽管 GetValue、Setvalue 在最后访问静态只读属性
  • 这完全等同于从字典中检索项目:var foo = new Dictionary&lt;String, Object&gt;(); /* add stuff */ var x = foo["Bar"];。如果您有六个不同的字典,每个字典都为“Bar”存储自己的个人值。 GetValueDependencyProperty 参数告诉DependencyObject 从它自己的内部存储中检索哪个值;如果该值存储在DependencyProperty 本身中,您将查询DependencyProperty不是 DependencyObject
【解决方案2】:

真正静态的是依赖属性描述符:

public static readonly DependencyProperty IsGrayProperty =    
    DependencyProperty.Register(
        "IsGray",
        typeof(bool),
        typeof(MyButton));

描述符只包含关于属性的元数据,不包含它的值。

与数据绑定一起使用并从代码访问的实际属性是实例之一:

public bool IsGray
{
    get
    {
        return (bool)GetValue(IsGrayProperty);
    }
    set
    {
        SetValue(IsGrayProperty, value);
    }
}

如您所见,它将 get 和 set 委托给基类 DependencyObject 的实例方法 GetValueSetValue

在内部,DependencyObject 维护一个条目数组(在实例字段中),其中存储了其依赖项属性的实际值。每个实例都有自己的数组,实际值位于其中一个条目中。因此,它永远不会与其他实例共享。因此,SetValue 改变了当前按钮实例的状态,而不是任何静态状态。

静态IsGrayProperty 描述符仅用于确定条目数组的索引、执行验证等。IsGrayProperty 是静态的这一事实使得思考起来有点反直觉,但无论如何,依赖属性值是依赖对象的每个实例,并且不共享。

【讨论】:

  • 感谢 Felix,通过使用 GetValue 和 SetValue,我正在访问注册的静态 IsGray 属性,在这种情况下,静态属性一次只有一个值,因此所有控件都应该相同实现了,但没有发生,我想知道依赖属性实际上是如何工作的
  • 不,不,不。通过使用 GetValue 和 SetValue,您可以访问一个包含条目数组的实例字段,每个实例都是私有的。 IsGrayProperty 描述符仅用于确定数组的索引、执行验证等。GetValue 和 SetValue 读取和写入的实际值位于入口数组的入口处,每个实例都有自己的入口数组。 IsGrayProperty 是静态的这一事实使得考虑它有点反直觉,但是,依赖属性值是每个实例的,并且不共享。
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2011-11-07
  • 2011-03-08
  • 1970-01-01
相关资源
最近更新 更多