XAML 加载和依赖项属性
WPF 当前对其 XAML 处理器的实现在本质上能够识别依赖项属性。 在加载二进制 XAML 并处理作为依赖项属性的特性时,WPF XAML 处理器针对依赖项属性使用属性系统方法。 这会有效地跳过属性包装。 在实现自定义依赖项属性时,必须考虑此行为,而且应当避免将任何其他代码放在除属性系统方法 GetValue 和 SetValue 以外的属性包装中。
本主题包括下列各节。
- 先决条件
- WPF XAML 加载器的实现和性能
- 自定义依赖项属性的含义
- 相关主题
先决条件
本主题假设您同时从使用者和作者的角度理解了依赖项属性,而且已经阅读了依赖项属性概述和自定义依赖项属性。 您还应当已经阅读了 XAML 概述 (WPF)和 XAML 语法详述。
WPF XAML 加载器的实现和性能
出于实现方面的原因,以下操作的计算成本较低:将某个属性标识为依赖项属性并访问属性系统的 SetValue 方法来设置该属性(而不是使用属性包装及其 setter)。 这是由于只有当您知道由标记结构和各个字符串所指示的类型和成员关系时,XAML 处理器才能推断支持代码的整个对象模型。
可通过 xmlns 和程序集特性的组合来查找类型,但是在标识成员、确定支持将哪个成员设置为特性,以及解析属性值支持哪些类型时,则会要求使用 PropertyInfo 进行广泛的反射。 由于给定类型的依赖项属性可作为存储表通过属性系统来进行访问,因此,WPF 对其 XAML 处理器的实现将使用该表,并推断可以通过以下方法来更高效地设置任何给定的属性 ABC:针对包含 DependencyObject 派生类型调用 SetValue,并使用依赖项属性标识符 ABCProperty。
自定义依赖项属性的含义
由于当前 WPF 为属性设置实现的 XAML 处理器行为会完全跳过包装,因此您不应当将任何其他逻辑放在自定义依赖项属性的包装集定义中。 如果您将此类逻辑放在包装集定义中,则当在 XAML(而不是代码)中设置属性时,将不会执行此类逻辑。
同样,在 XAML 处理器中,从 XAML 处理中获取属性值的其他方面也使用 GetValue,而不是使用包装。 因此,您还应当避免在 get 定义中使用除 GetValue 调用以外的任何其他实现。
下面的示例是所建议的具有包装的依赖项属性定义,其中的属性标识符存储为一个 public static readonly 字段,get 和 set 定义中仅包含定义依赖项属性支持所必需的属性系统方法,而不包含任何其他代码。
Public Shared ReadOnly AquariumGraphicProperty As DependencyProperty = DependencyProperty.Register("AquariumGraphic", GetType(Uri), GetType(AquariumObject), New FrameworkPropertyMetadata(Nothing, FrameworkPropertyMetadataOptions.AffectsRender, New PropertyChangedCallback(AddressOf OnUriChanged)))
Public Property AquariumGraphic() As Uri
Get
Return CType(GetValue(AquariumGraphicProperty), Uri)
End Get
Set(ByVal value As Uri)
SetValue(AquariumGraphicProperty, value)
End Set
End Property
public static readonly DependencyProperty AquariumGraphicProperty = DependencyProperty.Register(
"AquariumGraphic",
typeof(Uri),
typeof(AquariumObject),
new FrameworkPropertyMetadata(null,
FrameworkPropertyMetadataOptions.AffectsRender,
new PropertyChangedCallback(OnUriChanged)
)
);
public Uri AquariumGraphic
{
get { return (Uri)GetValue(AquariumGraphicProperty); }
set { SetValue(AquariumGraphicProperty, value); }
}