我已经在SO和其他站点上阅读了很多有关依赖项属性的信息。但是,确实还没有找到很好的解释,仍然感到困惑。我同时使用SL和WPF。在实现方面,它们在SL和WPF中是否有所不同?为什么我们真的需要它们?它们是静态的,意味着它们的值是共享的吗?为什么MS引入依赖项属性的原因?
赏金:
我正在寻找更彻底,完整的答案。
最佳答案
答案在于名称本身,尽管“依赖”一词在软件开发中是如此含糊,以至于尚不清楚其含义。
依赖项属性是一个对象的属性,其值取决于另一个对象。因此,例如:FontFamily
的TextBox
属性的值可以(通常确实)取决于其容器的FontFamily
属性。如果更改容器上的属性,则TextBox
上的值将更改。Text
的TextBox
属性的值可以取决于绑定的数据源。当绑定属性的值更改时,Text
属性的值更改。Opacity
的Label
属性的值可以取决于动画情节提要板,在通常情况下,您已将UI元素设置为响应某些事件而淡入或淡出。
任何UI元素上各种属性的值都可以取决于您应用于它们的样式。
依赖背后的中心概念是,依赖的事物应该从依赖的事物中获取属性值。这就是为什么将依赖项属性实现为CLR属性,其getter调用方法的原因。
当TextBox
或正在渲染它的东西需要知道其FontFamily
是什么时,FontFamily
getter会调用GetValue
方法。该方法从容器,动画或绑定中查找值。
该方法有很多复杂性。例如,如果该值是继承的,则其工作方式与WPF在资源字典中查找样式的方式非常相似:它将在本地字典中查找以找到该值,并且如果没有条目,它将在其父级字典中查找,并且因此一直到找到值或到达层次结构的顶部为止,在这种情况下,它将使用默认值。
如果您查看依赖项属性的实现,就会发现这一点。依赖项对象的字典可能包含也可能不包含给定属性的条目。 GetValue
方法从该字典中获取值(这是具有依赖项属性的对象可以具有覆盖其继承自其内容的局部值的方式),如果找不到该值,它将使用有关该属性的元信息来找出应该看的地方。
由于该元信息对于类中的每个对象都是相同的(即TextBox.Text
对于每个TextBox
都相同),因此存储在其中的字典是该类的静态属性。
因此,当您看到这样的代码时:
static Button()
{
// Register the property
Button.IsDefaultProperty =
DependencyProperty.Register("IsDefault",
typeof(bool), typeof(Button),
new FrameworkPropertyMetadata(false,
new PropertyChangedCallback(OnIsDefaultChanged)));
}
发生的情况是,已将定义所有
IsDefault
对象上的Button
属性的元信息添加到该字典中。当您看到以下内容时:public bool IsDefault
{
get { return (bool)GetValue(Button.IsDefaultProperty); }
set { SetValue(Button.IsDefaultProperty, value); }
}
您所看到的是基于该元信息查找属性值(从本地字典,父对象或其他对象)的getter方法。
还记得我曾说过,getter第一次查找属性值是在对象的本地字典中吗?设置器中的
SetValue
方法是将条目添加到字典中的方式(如果曾经被调用过,只有当您通过显式设置属性来覆盖依赖项时,即“我想要这个TextBox
无论窗口中的其他控件正在使用什么,都可以在Consolas
中显示文本。”)。我们从这种看似复杂的系统中获得的一个巨大的显着好处是,对象的依赖属性只有在设置了属性的情况下才会消耗内存。如果我创建10,000个
TextBox
控件并将它们添加到Window
,则其中没有一个控件实际上包含对FontFamily
对象的引用。那是我没有为其分配内存的10,000个对象引用,并且垃圾收集器没有检查。实际上,如果TextBox
具有100个依赖项属性(并且确实如此),则每当创建TextBox
时,即没有为100个后备字段分配内存。如果明确设置依赖项属性,则它们只会消耗内存。由于从未明确设置UI对象上的绝大多数属性,因此可以节省大量成本。
关于.net - 揭开依赖属性的神秘面纱,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/4347135/