我一直在阅读几本书中的依赖属性,但都有一个共同点,它们只是告诉我们它们是如何实现的(使用static readonly DependencyProperty
等)但是没有告诉它们从内部工作的确切方式。
我的意思是它们被实现为静态但仍然适用于所有对象 第二点混淆是附加属性。
是否有可以轻松解释所有这些概念的教程?
答案 0 :(得分:32)
我的依赖属性如何工作的心智模型:
任何DependencyObject
类都实现了两个特殊属性。一个是类的静态属性,是DependencyProperty
个对象的字典。该类的每个实例都可以查看该字典,以查找有关每个DependencyProperty
的元信息 - 属性的名称,类型,在获取和设置时必须调用的任何回调,它如何参与属性继承,等等上。注册依赖项属性时,您要在此字典中添加一个条目。
另一个属性是一个实例属性:它是一个由DependencyProperty
键控的字典,其中包含每个DependencyProperty
的本地值(如果已设置)。 / p>
您在CLR属性的setter和getter中实现的SetValue
和GetValue
方法基本上是对类固醇的懒惰评估。它们不是在支持字段中存储和检索属性的值,而是在值字典中存储和检索属性的值。
依赖属性的神奇之处在于GetValue
和SetValue
实际上做的事情。
GetValue
在对象的值字典中查找属性的值。如果找不到它,则在父元素上调用GetValue
,以获取父元素认为该值的内容。例如,当您在TextBox
中创建Window
时,查看TextBox
的{{1}}的任何内容实际上都在调用FontFamily
。除非您明确设置了字体,否则其字典中没有该属性的条目。所以GetValue
向父元素询问值。父元素可以设置或不设置GetValue
;如果没有,其调用FontFamily
以返回其父级的值。依此类推,直到达到GetValue
对象并找到实际的Window
值。
如果您在FontFamily
上设置FontFamily
,TextBox
会将值存储在值字典中。下次任何需要获取SetValue
FontFamily
的值时,TextBox
会在字典中找到值并返回它,因此不需要询问父元素
如果您在GetValue
上设置FontFamily
,Window
不仅会更新SetValue
的值字典中的值,还会触发属性更改事件,即所有内容依赖于财产听到。 (这就是为什么它们被称为依赖属性,请记住。)如果依赖于属性的东西本身就是依赖属性,它会触发自己的属性更改事件。这就是更改Window
上的FontFamily
更改窗口中每个控件的字体的方式,并提示WPF重新呈现已更改的控件。
附加属性使用相同的方法。任何可以附加属性的对象都有一个字典,其中存储了附加属性的值。当您在XAML中的Window
上设置Grid.Column
时,您只需向{{1}添加一个条目我的字典。当CheckBox
需要知道CheckBox
所在的列时,它会从该字典中查找值。在对象上设置Grid
到CheckBox
时,该对象的字典将包含一个新属性 - 一个包含每个Grid.IsSharedSizeScope
的宽度/高度的字典。
我应该强调这是我的心理模型。我没有和Reflector坐下来看看True
,SharedSizeKey
和Register
的实际实现,以弄清楚它们是如何工作的。我可能错了细节。但它是一个准确预测这些东西表现如何的模型,所以它已经足够好了。
在字典中存储属性值的概念对于C#程序员来说非常奇怪。不过,这对Python程序员来说是老生常谈的。在Python中,所有类属性 - 事实上所有对象 - 都存储在字典中,因此您可以通过属性访问器或仅通过查找它们来获取它们的值。依赖属性和附加属性只是另一种方式,在这种方式中,窃取了Java值得窃取的所有内容,现在正在掠夺Python。 (或者从Python掠夺它们的地方。)学习Python让我成为一个更好的C#程序员;我推荐给尚未完成它的任何C#开发人员。
答案 1 :(得分:6)
这是一个关于依赖属性http://www.wpftutorial.net/DependencyProperties.html的教程,它解释了它们的工作原理。
DependencyProperty对象在静态字段中的简要说明是,它表示属性的 description ,而不是属性的值。每个DependencyObject都有一个从DependencyProperty对象到其值的映射。
这也是附加属性的工作原理。因为每个DependencyObject都存储从任何DependencyProperty到值的映射,所以任何类型都可以创建新的DependencyProperty并在任何现有的DependencyObject上设置它。
答案 2 :(得分:2)
请看josh smith的这篇文章,其中还有一些其他信息
http://joshsmithonwpf.wordpress.com/2007/06/22/overview-of-dependency-properties-in-wpf/
答案 3 :(得分:0)
您可以在下面看到dependency property
创建custom control text box
的基本示例,其中不允许使用空格意味着用户无法在文本框中键入空格。
1)创建一个名为ValidatedTextBox
的类,并在此类文件中编写以下代码:
public class ValidatedTextBox : TextBox
{
public ValidatedTextBox()
{
}
public static readonly DependencyProperty IsSpaceAllowedProperty =
DependencyProperty.Register("IsSpaceAllowed", typeof(bool), typeof(ValidatedTextBox));
public bool IsSpaceAllowed
{
get { return (bool)base.GetValue(IsSpaceAllowedProperty); }
set { base.SetValue(IsSpaceAllowedProperty, value); }
}
protected override void OnPreviewKeyDown(KeyEventArgs e)
{
base.OnPreviewKeyDown(e);
if (!IsSpaceAllowed && (e.Key == Key.Space))
{
e.Handled = true;
}
}
}
2)现在将上述控件用于.XAML
文件
a)添加自定义控件文本框的命名空间,如下所示:
xmlns:CustomControls="clr-namespace: ValidatedTextBox;assembly= ValidatedTextBox "
b)现在,使用如下所示的自定义控件文本框:
<CustomControls:ValidatedTextBox IsSpaceAllowed="False" x:Name="MyTextBox" />
它将创建一个不允许空间的自定义控件文本框。因此,基本依赖属性允许添加功能,扩展任何控件的功能。