Che*_*eso 6 wpf dependency-properties
在WPF中,成为"依赖属性"意味着什么呢?
我阅读了微软的依赖属性概述,但它并没有真正吸引我.部分文章说:
样式和模板是使用依赖项属性的两个主要激励方案.样式对于设置定义应用程序用户界面(UI)的属性特别有用.样式通常定义为XAML中的资源.样式与属性系统交互,因为它们通常包含特定属性的"setter",以及根据另一个属性的实时值更改属性值的"触发器".
然后示例代码是这样的:
<Style x:Key="GreenButtonStyle">
<Setter Property="Control.Background" Value="Green"/>
</Style>
....
<Button Style="{StaticResource GreenButtonStyle}">I am green!</Button>
Run Code Online (Sandbox Code Playgroud)
但是我没有得到关于这一点的特别之处.这只是暗示,当我Style按下按钮到给定的样式时,我实际上是Background隐式设置的吗?这是它的关键吗?
Rob*_*ney 27
以下是依赖属性如何工作的解释,我总是希望有人为我写过.这是不完整的,也可能是错误的,但它将帮助您充分了解它们,以便您能够掌握所阅读的文档.
依赖属性是类似属性的值,可以通过DependencyObject类的方法获取和设置.它们可以(并且通常确实)看起来非常像CLR属性,但它们不是.这就是他们第一个令人困惑的事情.依赖属性实际上由几个组件组成.
这是一个例子:
Document是RichTextBox对象的属性.这是一个真正的CLR属性.也就是说,它有一个名称,一个类型,一个getter和一个setter,就像任何其他CLR属性一样.但与"普通"属性不同,该RichTextBox属性不仅仅在实例中获取和设置私有值.在内部,它的实现方式如下:
public FlowDocument Document
{
get { return (FlowDocument)GetValue(DocumentProperty); }
set { SetValue(DocumentProperty, value); }
}
Run Code Online (Sandbox Code Playgroud)
当您设置Document的值你就会被传递到通过SetValue,沿DocumentProperty.什么是那?如何GetValue获得它的价值?而且......为什么?
首先是什么.在RichTextBox命名上定义了一个静态属性DocumentProperty.声明此属性时,它是这样完成的:
public static DependencyProperty DocumentProperty = DependencyProperty.Register(
"Document",
typeof(FlowDocument),
typeof(RichTextBox));
Run Code Online (Sandbox Code Playgroud)
Register在这种情况下,该方法告诉依赖属性系统RichTextBox- 类型而不是实例 - 现在具有名为Documenttype 的依赖属性FlowDocument.此方法存储此信息......某处.确切地说,这是一个对我们隐藏的实现细节.
当为的setter Document属性调用SetValue,该SetValue方法着眼于DocumentProperty争论,验证它是真正属于一个性质RichTextBox,并且value是正确的类型,然后存储其新的价值...某处.DependencyObject这个实现细节的文档是腼腆的,因为你真的不需要知道它.在我的这个东西是如何工作的心理模型,我认为有类型的属性Dictionary<DependencyProperty, object>那是私有的DependencyObject,所以派生类(像RichTextBox),还看不出来,但GetValue并SetValue可以对其进行更新.但谁知道呢,也许它是由僧侣写在羊皮纸上的.
无论如何,这个值现在被称为"本地值",也就是说它是一个特定的值,RichTextBox就像普通的属性一样.
所有这一切的重点是:
GetValue并SetValue获取和设置它,但除非您使用依赖项属性系统执行某些操作,否则您可能不需要.什么样的东西?好吧,让我们来看看一些用例.
捆绑. 绑定到属性时,它必须是依赖项属性.这是因为Binding对象实际上并没有在目标上设置属性,而是调用SetValue目标对象.
样式. 将对象的依赖项属性设置为新值时,SetValue告诉样式系统您已执行此操作.这就是触发器如何工作:它们没有发现属性的值已经通过魔法改变了,依赖属性系统告诉他们.
动态资源. 如果您编写类似XAML Background={DynamicResource MyBackground},则可以更改MyBackground资源的值,并更新引用它的对象的背景.这也不是魔术; 动态资源调用SetValue.
动画. 动画通过操纵属性值来工作.那些必须是依赖属性,因为动画正在调用SetValue它们.
更改通知. 注册依赖项属性时,还可以指定SetValue在设置属性值时调用的函数.
价值继承. 注册依赖项属性时,可以指定它参与属性值继承.当您调用GetValue以获取对象的依赖项属性的值时,GetValue查看是否存在本地值.如果没有,它会遍历父对象链,查看该属性的本地值.
这就是你可以设置FontFamily一个Window神奇的东西(我经常使用那个词),窗口中的每个控件都使用新的字体.此外,它是如何在一个窗口中拥有数百个控件,而每个控件都没有FontFamily成员变量来跟踪它们的字体(因为它们没有本地值)但你仍然可以设置FontFamily任何一个控件(因为每个人DependencyObject拥有的值得隐藏的价值字典.
了解依赖属性试图解决的问题可能会有所帮助.
如果我们将Binding,Animation和Change Event模型放在一边,就像在其他答案中讨论过的那样,那么好处是内存使用,因此可以在窗口中托管数千个WPF对象.
如果窗口包含1000分Label的对象与每个Label具有通常的对象Foreground,Background,FontFamily,FontSize,FontWeight,等等,那么传统上这将消耗存储器,因为每个属性将具有私有支持字段,以存储该值.
大多数应用程序只会更改一些属性,其中大部分将保留其默认值.基本上非常浪费和冗余的信息(每个对象只在内存中保持相同的默认值)
这是依赖属性不同的地方.
// Lets register the Dependency Property with a default value of 20.5
public static readonly DependencyProperty ColumnWidthProperty =
DependencyProperty.Register("ColumnWidth", typeof(double), typeof(MyWPFControl), new UIPropertyMetadata(20.5, ColWitdhPropChanged));
public double ColumnWidth
{
get { return (double)GetValue(ColumnWidthProperty); }
set { SetValue(ColumnWidthProperty, value); }
}
Run Code Online (Sandbox Code Playgroud)
没有私人支持领域.注册依赖项属性时,可以指定默认值.因此,在大多数情况下,返回的值GetValue是默认值,该值仅存储一次,以覆盖Label应用程序所有窗口中对象的所有实例.
当使用SetValue它设置依赖项属性时,它将非默认值存储在由对象实例标识的集合中,以便在所有后续GetValue调用中返回.
因此,此存储方法仅消耗已从默认值更改的WPF对象的属性的内存.即仅与默认值的差异.
在WPF中,成为"依赖属性"意味着什么呢?
为了成为依赖属性,该属性实际上必须在类上静态地定义为DependencyProperty.依赖属性系统与标准CLR属性非常不同.
但是,依赖属性的处理方式却截然不同.类型静态定义依赖项属性,并提供默认值.在需要之前,运行时实际上不会为实例生成值.这提供了一个好处 - 在请求类型之前该属性不存在,因此您可以拥有大量属性而无需开销.
这就是使样式工作属性的原因,但是通过可视树允许附加属性,属性"继承"以及WPF依赖的许多其他东西也很重要.
例如,获取DataContext依赖项属性.通常,您DataContext为Window或UserControl 设置依赖项属性.默认情况下,该窗口中的所有控件DataContext都会自动"继承"其父级的属性,这允许您为控件指定数据绑定.使用标准CLR属性,您需要为窗口中的每个控件定义DataContext,以使绑定正常工作.
| 归档时间: |
|
| 查看次数: |
8277 次 |
| 最近记录: |