Read-only dependency properties (WPF .NET)

You can use read-only dependency properties to prevent property values being set from outside your code. This article discusses existing read-only dependency properties and the scenarios and techniques for creating a custom read-only dependency property.

Important

The Desktop Guide documentation for .NET 7 and .NET 6 is under construction.

Prerequisites

The article assumes a basic knowledge of dependency properties, and that you've read Dependency properties overview. To follow the examples in this article, it helps if you're familiar with Extensible Application Markup Language (XAML) and know how to write WPF applications.

Existing read-only dependency properties

Read-only dependency properties typically report state, and shouldn't be modifiable through a public accessor. For example, the Windows Presentation Foundation (WPF) framework implements the IsMouseOver property as read-only because its value should only be determined by mouse input. If IsMouseOver allowed other inputs, its value might become inconsistent with mouse input. Though not settable through a public accessor, many existing read-only dependency properties have values determined by multiple inputs.

Uses of read-only dependency properties

Read-only dependency properties aren't applicable in several scenarios where dependency properties normally offer a solution. Non-applicable scenarios include data binding, applying a style to a value, validation, animation, and inheritance. However, a read-only dependency property can be used as a property trigger in a style. For example, IsMouseOver is commonly used to trigger changes to the background, foreground, or other visible property of a control when the mouse is over it. The WPF property system detects and reports changes in read-only dependency properties, thus supporting property trigger functionality. Read-only dependency properties are also useful when implementing a collection-type dependency property where only the collection elements need to be writeable, not the collection object itself. For more information, see Collection-type dependency properties.

Note

Only dependency properties, not regular common language runtime properties, can be used as property triggers in a style.

Creating custom read-only dependency properties

Before creating a dependency property that's read-only, check the non-applicable scenarios.

The process of creating a read-only dependency property is in many ways similar to creating read-write dependency properties, with these distinctions:

  • When registering your read-only property, call RegisterReadOnly instead of Register.

  • When implementing the CLR property wrapper, make sure it doesn't have a public set accessor.

  • RegisterReadOnly returns DependencyPropertyKey instead of DependencyProperty. Store the DependencyPropertyKey in a nonpublic class member.

You can determine the value of your read-only dependency property using whatever logic you choose. The recommended way to set the property value, either initially or as part of runtime logic, is to use the overload of SetValue that accepts a parameter of type DependencyPropertyKey. Using SetValue is preferable to circumventing the property system and setting the backing field directly.

How and where you set the value of a read-only dependency property within your application will affect the access level you assign to the class member that stores the DependencyPropertyKey. If you only set the property value from within the class that registers the dependency property, you can use a private access modifier. For scenarios where the values of dependency properties affect each other, you can use paired PropertyChangedCallback and CoerceValueCallback callbacks to trigger value changes. For more information, see Dependency property metadata.

If you need to change the value of a read-only dependency property from outside the class that registers it, you can use an internal access modifier for the DependencyPropertyKey. For example, you might call SetValue from an event handler in the same assembly. The following example defines an Aquarium class that calls RegisterReadOnly to create the read-only dependency property FishCount. The DependencyPropertyKey is assigned to an internal static readonly field, so that code in the same assembly can change the read-only dependency property value.

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

Because the WPF property system doesn't propagate the DependencyPropertyKey outside your code, read-only dependency properties have better write security than read-write dependency properties. Use a read-only dependency property when you want to limit write-access to those who have a reference to the DependencyPropertyKey.

In contrast, the dependency property identifier for read-write dependency properties is accessible through the property system, no matter what access modifier you assign it. For more information, see Dependency property security.

See also