只读依赖属性 (WPF .NET)
可以使用只读依赖属性来防止从代码外部设置属性值。 本文讨论现有的只读依赖属性,以及创建自定义只读依赖属性的方案和技术。
先决条件
本文假定你对依赖属性有基本的了解,并且已阅读依赖属性概述。 若要理解本文中的示例,还应当熟悉 Extensible Application Markup Language (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 回叫来触发值更改。 有关详细信息,请参阅依赖属性元数据。
如果需要从注册只读依赖属性的类外部更改其值,可以为 DependencyPropertyKey
使用 internal
访问修饰符。 例如,你可以从同一程序集中的事件处理程序调用 SetValue
。 以下示例定义了一个 Aquarium 类,该类调用 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
的引用,请使用只读依赖属性。
相反,无论为其分配什么访问修饰符,读写依赖属性的依赖属性标识符都可以通过属性系统访问。 有关详细信息,请参阅依赖属性安全性。