可以使用只读依赖项属性来防止从代码外部设置属性值。 本文讨论现有的只读依赖属性以及创建自定义只读依赖属性的方案和技术。
先决条件
本文假设对依赖属性有一个基本的了解,并且你已阅读 依赖项属性概述。 若要遵循本文中的示例,如果熟悉可扩展应用程序标记语言(XAML),并且知道如何编写 WPF 应用程序,则很有帮助。
现有的只读依赖项属性
只读依赖项属性通常报告状态,不应通过 public
访问器进行修改。 例如,Windows Presentation Foundation (WPF) 框架将属性实现 IsMouseOver 为只读,因为它的值应仅由鼠标输入确定。 如果 IsMouseOver
允许其他输入,则其值可能与鼠标输入不一致。 虽然不是通过 public
访问器设置的,但许多现有的只读依赖属性具有由多个输入确定的值。
只读依赖属性的使用
只读依赖属性在多个场景中并不适用,而这些场景依赖属性通常能提供解决方案。 不适用的方案包括数据绑定、向值应用样式、验证、动画和继承。 但是,只读依赖属性可用作样式中的属性触发器。 例如, IsMouseOver 通常用于在鼠标悬停在控件上时触发对控件的背景、前景或其他可见属性的更改。 WPF 属性系统检测和报告只读依赖属性中的更改,从而支持属性触发器功能。 实现集合类型依赖属性时,只读依赖属性也很有用,其中只有集合元素需要可写入,而不是集合对象本身。 有关详细信息,请参阅 集合类型依赖项属性。
注释
只有依赖属性(而不是常规的公共语言运行时属性)可以用作样式中的属性触发器。
创建自定义只读依赖项属性
在创建只读依赖项属性之前,请检查 不适用的方案。
创建只读依赖属性的过程在许多方面类似于创建读写依赖属性,这些区别如下:
注册只读属性时,调用 RegisterReadOnly 而不是 Register。
实现 CLR 属性包装器时,请确保它没有公共
set
访问器。RegisterReadOnly
返回 DependencyPropertyKey 而不是 DependencyProperty. 将DependencyPropertyKey
存储在一个非公共类成员中。
可以使用所选的任何逻辑来确定只读依赖属性的值。 建议的设置属性值的方法是,无论是初始设置还是作为运行时逻辑的一部分,都应使用接受DependencyPropertyKey
类型参数的SetValue重载。 使用 SetValue
比直接设置后台字段而绕过属性系统更为可取。
设置应用程序中只读依赖属性的值的方式和位置会影响分配给存储该 DependencyPropertyKey
属性的类成员的访问级别。 如果仅从注册依赖属性的类中设置属性值,则可以使用 private
访问修饰符。 对于依赖属性的值相互影响的情况,可以使用配对 PropertyChangedCallback 和 CoerceValueCallback 回调来触发值更改。 有关详细信息,请参阅 Dependency 属性元数据。
如果需要从注册它的类外部更改只读依赖属性的值,可以为该属性使用 internal
访问修饰符。 例如,可以从同一程序集中的事件处理程序调用 SetValue
。 下面的示例定义了一个用于调用 RegisterReadOnly
创建只读依赖属性 FishCount
的水族馆类。 将 DependencyPropertyKey
指派给一个 internal static readonly
字段,以便同一程序集中的代码可以修改只读依赖属性的值。
public class Aquarium : DependencyObject
{
// Register a dependency property with the specified property name,
// property type, owner type, and property metadata.
// Assign DependencyPropertyKey to a nonpublic field.
internal static readonly DependencyPropertyKey FishCountPropertyKey =
DependencyProperty.RegisterReadOnly(
name: "FishCount",
propertyType: typeof(int),
ownerType: typeof(Aquarium),
typeMetadata: new FrameworkPropertyMetadata());
// Declare a public get accessor.
public int FishCount =>
(int)GetValue(FishCountPropertyKey.DependencyProperty);
}
Public Class Aquarium
Inherits DependencyObject
' Register a dependency property with the specified property name,
' property type, owner type, And property metadata.
' Assign DependencyPropertyKey to a nonpublic field.
Friend Shared ReadOnly FishCountPropertyKey As DependencyPropertyKey =
DependencyProperty.RegisterReadOnly(
name:="FishCount",
propertyType:=GetType(Integer),
ownerType:=GetType(Aquarium),
typeMetadata:=New FrameworkPropertyMetadata())
' Declare a public get accessor.
Public ReadOnly Property FishCount As Integer
Get
Return GetValue(FishCountPropertyKey.DependencyProperty)
End Get
End Property
End Class
由于 WPF 属性系统不会传播 DependencyPropertyKey 代码外部,只读依赖属性具有比读写依赖项属性更好的写入安全性。 当您想限制对DependencyPropertyKey
具有引用的用户的写访问权限时,请使用只读依赖属性。
相比之下,无论分配什么访问修饰符,都可以通过属性系统访问读写依赖属性的依赖属性标识符。 有关详细信息,请参阅 依赖项属性安全性。