赏金:
我正在寻找一个更彻底,完整的答案。
依赖属性是一个对象的属性,其值取决于某个其他对象。所以,例如:
> TextBox的FontFamily属性的值可以(通常也可以)取决于其容器的FontFamily属性。如果更改容器上的属性,则TextBox上的值将更改。
> TextBox的Text属性的值可以取决于绑定的数据源。当绑定属性的值更改时,Text属性的值会更改。
>标签的Opacity属性的值可以取决于动画故事板,在常见的情况下,您已经设置了一个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))); }
发生的是在所有Button对象中定义IsDefault属性的元信息都被添加到该字典中。当你看到这个:
public bool IsDefault { get { return (bool)GetValue(Button.IsDefaultProperty); } set { SetValue(Button.IsDefaultProperty,value); } }
你看到的是getter方法,它根据该元信息查找属性的值(来自本地字典,父对象或其他)。
记住我如何说,getter看起来找到一个属性的值的第一个地方在对象的本地字典中? setter中的SetValue方法是如何将这个条目添加到字典中(如果它被调用,那么只有当你通过显式地设置属性来覆盖依赖关系时,就是说“我希望这个TextBox能够显示文本Consolas,而不管窗口中的其他控件使用什么。“)。
我们从这种显然复杂的系统中获得的巨大优势是,对象的依赖属性只有在设置时才消耗内存。如果我创建10,000个TextBox控件并将它们添加到一个窗口中,其中一个实际上不包含对FontFamily对象的引用。这是10,000个对象引用,我没有分配内存,垃圾收集器没有检查。实际上,如果一个TextBox有100个依赖属性(而且它只是大约),每当你创建一个TextBox,这是100个后备字段,你不分配内存。如果您明确设置它们,则依赖属性仅消耗内存。由于UI对象的绝大多数属性从未被明确设置,所以这些都是非常好的节省。