只读依赖属性 (WPF .NET)

可以使用只读依赖属性来防止从代码外部设置属性值。 本文讨论现有的只读依赖属性,以及创建自定义只读依赖属性的方案和技术。

重要

面向 .NET 7 和 .NET 6 的桌面指南文档正在撰写中。

先决条件

本文假定你对依赖属性有基本的了解,并且已阅读依赖属性概述。 若要理解本文中的示例,还应当熟悉 Extensible Application Markup Language (XAML) 并知道如何编写 WPF 应用程序。

现有只读依赖属性

只读依赖属性通常报告状态,不应通过 public 访问器进行修改。 例如,Windows Presentation Foundation (WPF) 框架将 IsMouseOver 属性实现为只读,因为它的值应仅由鼠标输入确定。 如果 IsMouseOver 允许其他输入,则其值可能与鼠标输入不一致。 虽然无法通过 public 访问器设置,但许多现有的只读依赖属性具有由多个输入确定的值。

只读依赖属性的使用

对于依赖属性通常提供解决方案的几种场景,只读依赖属性不适用。 不适用的场景包括数据绑定、将样式应用于值、验证、动画和继承。 但是,只读依赖属性可以用作样式中的属性触发器。 例如,IsMouseOver 通常用于在鼠标悬停在控件上时触发对控件的背景、前景或其他可见属性的更改。 WPF 属性系统检测并报告只读依赖属性的更改,从而支持属性触发功能。 只读依赖属性在实现集合类型依赖属性时也很有用,其中只有集合元素需要是可写的,而不是集合对象本身。 有关详细信息,请参阅集合类型依赖属性

注意

只有依赖属性,而不是常规的公共语言运行时属性,可以用作样式中的属性触发器。

创建自定义只读依赖属性

在创建只读依赖属性之前,请检查不适用的场景

创建只读依赖属性的过程在许多方面类似于创建读写依赖属性,但有以下区别:

可以使用选择的任何逻辑来确定只读依赖属性的值。 设置属性值的建议方法(最初或作为运行时逻辑的一部分)是使用接受 DependencyPropertyKey 类型参数的 SetValue 的重载。 使用 SetValue 比绕过属性系统和直接设置支持字段更可取。

在应用程序中设置只读依赖属性值的方式和位置将影响分配给存储 DependencyPropertyKey 的类成员的访问级别。 如果仅从注册依赖属性的类中设置属性值,可以使用 private 访问修饰符。 对于依赖属性值相互影响的场景,可以使用配对 PropertyChangedCallbackCoerceValueCallback 回叫来触发值更改。 有关详细信息,请参阅依赖属性元数据

如果需要从注册只读依赖属性的类外部更改其值,可以为 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 的引用,请使用只读依赖属性。

相反,无论为其分配什么访问修饰符,读写依赖属性的依赖属性标识符都可以通过属性系统访问。 有关详细信息,请参阅依赖属性安全性

另请参阅