WPF中依赖属性的用途

5

我很难找到依赖属性的好理由。为什么System.Controls.TextBox的“Text”属性是依赖属性而不是普通属性?它作为依赖属性有什么好处?

我试图实现的其中一件事是将ValidationRules属性添加到我的UserControl中,该属性将包含其他验证规则。就像这样:

<customControls:RequiredTextBox.ValidationRules>
                        <validators:NotNullOrEmptyValidationRule ErrorMessage="FirstName cannot be null or empty"/>
                    </customControls:RequiredTextBox.ValidationRules>

问题在于我不确定ValidationRules属性应该是DependencyProperty还是普通属性。
上述代码会产生以下错误:
{"Cannot add element to 'ValidationRules'; the property value is null.  Error at object 'LearningWPF.ValidationRules.NotNullOrEmptyValidationRule' in markup file 'LearningWPF;component/addcustomerwindow.xaml' Line 35 Position 66."}

这里是ValidationRules属性:

 public static readonly DependencyProperty ValidationRulesProperty =
            DependencyProperty.Register("ValidationRules",
                                        typeof (Collection<ValidationRule>), typeof (RequiredTextBox),
                                        new FrameworkPropertyMetadata(null)); 

        public Collection<ValidationRule> ValidationRules
        {
            get { return (Collection<ValidationRule>)GetValue(ValidationRulesProperty); }
            set { SetValue(ValidationRulesProperty, value); }
        }

ValidationRules是什么类型?看起来你正在尝试将一个对象添加到集合类型中,但还没有实例化该集合。 - Martin Harris
在添加项目之前,您需要实例化集合。在 RequiredTextBox 类的构造函数中添加以下代码:ValidationRules = new Collection<ValidationRule>(); 现在,您可以通过 xmal 向其添加项目了。 - Martin Harris
谢谢!我以为我已经初始化了它,但那段代码被注释掉了。谢谢你的帮助! - azamsharp
现在,在上面的代码中,我将ValidationRules设为了依赖属性。这样做有什么原因吗?因为它作为普通属性正常工作,所以我应该将其设为依赖属性吗? - azamsharp
我已经编辑了我的回答,以回应您最新的问题。 - Martin Harris
3个回答

8
其主要好处有两个:
第一,只有在使用时才会创建依赖属性,这意味着TextBox类可以非常高效,具有较低的内存占用,因为它只有少量实际属性占用堆上的空间。这在WPF中尤其重要,因为所有控件都只是越来越特定类型的集合。如果每个内部类型声明数十个属性以定义行为和外观,则高级控件(如按钮)的大小将达到具有大约一百个属性的类的水平。
第二个好处是,依赖属性可以与创建它们的类型不同的对象绑定。这允许控件设置Grid.Column属性,而Grid控件可以读取并用于布局。这意味着我们不需要成百上千的装饰器类提供其他控件所需的小功能。这意味着xmal更加直观和易读。
编辑以解决您修订后问题中的示例:
虽然您的验证属性不会因为成为依赖属性而获得太多好处(基本上出于目前所有答案中提到的原因,我只能看到我的内存占用评论真正发挥作用),并且它确实不像文本框的Text属性那样有优势,您可能希望对其进行绑定或者根据其他输入进行更改,但我仍然会将其实现为依赖属性。我的理由很简单:您不会获得太多好处,但这也不会花费您任何代价 - 我从未希望在自定义控件中使用基本属性,而当我开始编写它们时,我经常将我的基本属性升级为依赖属性,因为我想要一些额外的功能。
简而言之,尽管依赖属性比普通属性更复杂,但除非有充分的理由否则我仍然会将其用作WPF控件的默认标准。就像属性是类的标准一样,即使字段更容易实现。

你能列出几个依赖属性,这样我就能更好地了解你的自定义控件吗? - azamsharp

5
我认为主要的好处如下:
  1. 一流的数据绑定支持。
  2. 清晰的附加属性语义。
  3. “依赖”属性值。
最后一个点非常重要。
在引入依赖属性之前,一个值可能需要具有本地值、可动画值、可覆盖值、可样式化值、可模板化值,这将需要声明多个属性/字段/字典条目,以及复杂的状态+优先级管理。
依赖属性可以让你在只声明一个属性的情况下获得所有这些功能。但是,在您的情况下,如果您不需要利用这些功能,则可能不希望将您的ValidationRules声明为DependencyProperty。
如果您确实需要,您将需要对集合进行不同的处理(例如,对于非空集合)。在这个特定的例子中,我会使用Reflector来查看.NET TextBox如何实现其验证集合,并看看是否可以重用或复制代码。
除非您确定自己的轮子会更好,否则没有重新发明轮子的意义。我的个人经验是,我重新发明的轮子往往会缺少东西。
正如Martin Harris已经指出的那样,依赖属性可以通过将属性值抛入字典中来限制内存占用,但在依赖属性出现之前,Microsoft就已经做到了这一点。
Martin还提到了附加属性,但是在依赖属性出现之前(至少在设计器中)也已经存在了。使用依赖属性实现的附加属性更加清晰。

2

如果您想使用绑定填充属性的值,那么必须使用依赖属性。如果它只是一个普通属性,您无法将Text属性绑定到您的视图模型对象的属性上。


网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接