依赖属性WPF

时间:2010-06-25 04:40:30

标签: c# wpf dependency-properties

我一直在阅读几本书中的依赖属性,但都有一个共同点,它们只是告诉我们它们是如何实现的(使用static readonly DependencyProperty等)但是没有告诉它们从内部工作的确切方式。

我的意思是它们被实现为静态但仍然适用于所有对象 第二点混淆是附加属性。

是否有可以轻松解释所有这些概念的教程?

4 个答案:

答案 0 :(得分:32)

我的依赖属性如何工作的心智模型:

任何DependencyObject类都实现了两个特殊属性。一个是类的静态属性,是DependencyProperty个对象的字典。该类的每个实例都可以查看该字典,以查找有关每个DependencyProperty的元信息 - 属性的名称,类型,在获取和设置时必须调用的任何回调,它如何参与属性继承,等等上。注册依赖项属性时,您要在此字典中添加一个条目。

另一个属性是一个实例属性:它是一个由DependencyProperty键控的字典,其中包含每个DependencyProperty的本地(如果已设置)。 / p>

您在CLR属性的setter和getter中实现的SetValueGetValue方法基本上是对类固醇的懒惰评估。它们不是在支持字段中存储和检索属性的值,而是在值字典中存储和检索属性的值。

依赖属性的神奇之处在于GetValueSetValue实际上做的事情。

GetValue在对象的值字典中查找属性的值。如果找不到它,则在父元素上调用GetValue,以获取父元素认为该值的内容。例如,当您在TextBox中创建Window时,查看TextBox的{​​{1}}的任何内容实际上都在调用FontFamily。除非您明确设置了字体,否则其字典中没有该属性的条目。所以GetValue向父元素询问值。父元素可以设置或不设置GetValue;如果没有,调用FontFamily以返回父级的值。依此类推,直到达到GetValue对象并找到实际的Window值。

如果您在FontFamily上设置FontFamilyTextBox会将值存储在值字典中。下次任何需要获取SetValue FontFamily的值时,TextBox会在字典中找到值并返回它,因此不需要询问父元素

如果您在GetValue上设置FontFamilyWindow不仅会更新SetValue的值字典中的值,还会触发属性更改事件,即所有内容依赖于财产听到。 (这就是为什么它们被称为依赖属性,请记住。)如果依赖于属性的东西本身就是依赖属性,它会触发自己的属性更改事件。这就是更改Window上的FontFamily更改窗口中每个控件的字体的方式,并提示WPF重新呈现已更改的控件。

附加属性使用相同的方法。任何可以附加属性的对象都有一个字典,其中存储了附加属性的值。当您在XAML中的Window上设置Grid.Column时,您只需向{{1}添加一个条目我的字典。当CheckBox需要知道CheckBox所在的列时,它会从该字典中查找值。在对象上设置GridCheckBox时,该对象的字典将包含一个新属性 - 一个包含每个Grid.IsSharedSizeScope的宽度/高度的字典。

我应该强调这是我的心理模型。我没有和Reflector坐下来看看TrueSharedSizeKeyRegister实际实现,以弄清楚它们是如何工作的。我可能错了细节。但它是一个准确预测这些东西表现如何的模型,所以它已经足够好了。

在字典中存储属性值的概念对于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" /> 

它将创建一个不允许空间的自定义控件文本框。因此,基本依赖属性允许添加功能,扩展任何控件的功能。