Yup, awkward creatures but they do exist! :)

To be honest I came across these only recently and decided to share this (potentially) valuable information as well -- you cannot use it if you do not know it's there.

Why do we need read-only dependency properties?

There is a certain brand of dependency properties within the WPF framework that are used primarily for state determination. Often multiple conditions affect certain control state thus calculating and setting the state value directly is not feasible and generally leads to unpredictable and inconsistent results.

Here is an example -- the UIElement.IsMouseOver dependency property (a common property trigger) is in fact a read-only dependency property. OK, you haven't thought of modifying its value manually, but even if you did, the compiler would error out with something like 'IsMouseOver' property is read-only and cannot be set from markup"!  as it does not make sense to tamper with the surfacing state controlled by the mouse input.

So, how do we benefit from them?

As read-only dependency properties do not provide public setters, they have a limited range of application and certainly are not suitable for data binding, styling, and animations. Still, read-only dependency properties are a perfect match for style property trigger scenarios -- on one hand you cannot use regular CLR properties here and in most cases the property trigger is namely a state determining value that should not be subject to external modifications.

How to declare a read-only dependency property?

We will use a small sample application for this demo -- the CustomTickerControl (ok, ok -- it is VERY contrived but it just illustrates a point here;)). We will define the IsTick read-only dependency property that serves as a style property trigger to swap the control template of the CustomTickerControl -- the control displays TICK! on odd seconds, and TACK! on even ones. We will also need a timer control to re-evaluate the value of the read-only property on every second.

Here is the property registration:


Note that the DependencyProperty.RegisterReadOnly(...) method returns a DependencyPropertyKey object instead of the regular DependencyProperty. It is a good idea to mark the key as private or internal as otherwise the property would still be settable from the outside world -- there is an overload of the DependencyObject.SetValue(...) method that identifies the dependency property by its DependencyPropertyKey. The actual public read-only property is exposed via the DependencyPropertyKey.DependencyProperty property.

Let's define the timer control:


And here is the Tick event  handler as well -- the IsTick property value is updated based on whether the second is even or odd:


Notice the DependencyObject.SetValue(...) overload used here -- as discussed above, the DependencyPropertyKey can and is used to identify and set the value of a dependency property thus it is important not to expose the key publicly if you are implementing a read-only dependency property.

The corresponding XAML code goes here -- nothing fancy, just swapping the control template in the style property triggers:



Let's run it:



Hope this helps.

Related Posts


Comments are disabled in preview mode.