WPF Concepts—Support for Multiple Providers
|Visual C# Tutorials|
|.NET Framework Tutorials|
|© 2007 Sams Publishing|
Support for Multiple Providers
WPF contains many powerful mechanisms that independently attempt to set the value of dependency properties. Without a well-defined mechanism for handling these disparate property value providers, the system would be a bit chaotic and property values could be unstable. Of course, as their name indicates, dependency properties were designed to depend on these providers in a consistent and orderly manner.
Figure 3.5 illustrates the five-step process that WPF runs each dependency property through in order to calculate its final value. This process happens automatically thanks to the built-in change notification in dependency properties.
Step 1: Determine Base Value
Most of the property value providers factor into the base value calculation. The following list reveals the eight providers that can set the value of most dependency properties, in order from highest to lowest precedence:
- Local value
- Style triggers
- Template triggers
- Style setters
- Theme style triggers
- Theme style setters
- Property value inheritance
- Default value
You've already seen some of the property value providers, such as property value inheritance. Local value technically means any call to
DependencyObject.SetValue, but this is typically seen with a simple property assignment in XAML or procedural code (because of the way dependency properties are implemented, as shown previously with
Button.IsDefault). Default value refers to the initial value registered with the dependency property, which naturally has the lowest precedence. The other providers, which all involve styles and templates, are explained further in Chapter 10.
This order of precedence explains why
FontStyle were not impacted by property value inheritance in Listing 3.4. The setting of
StatusBar's font properties to match system settings is done via theme style setters (#6 in the list). Although this has precedence over property value inheritance (#7 in the list), you can still override these font settings using any mechanism with a higher precedence, such as simply setting local values on the
Step 2: Evaluate
If the value from step one is an expression (an object deriving from
System.Windows.Expression), then WPF performs a special evaluation step to convert the expression into a concrete result. In version 3.0 of WPF, expressions only come into play when using dynamic resources or data binding. Future versions of WPF may enable additional kinds of expressions.
Step 3: Apply Animations
If one or more animations are running, they have the power to alter the current property value (using the value after step 2 as input) or completely replace it. Therefore, animations can trump all other property value providers—even local values! This is often a stumbling block for people who are new to WPF.
Step 4: Coerce
After all the property value providers have had their say, WPF takes the almost-final property value and passes it to a
CoerceValueCallback delegate, if one was registered with the dependency property. The callback is responsible for returning a new value, based on custom logic. For example, built-in WPF controls such as
ProgressBar use this callback to constrain its
Value dependency property to a value between its
Maximum values, returning
Minimum if the input value is less than
Maximum if the input value is greater than
Step 5: Validate
Finally, the potentially-coerced value is passed to a
ValidateValueCallback delegate, if one was registered with the dependency property. This callback must return
true if the input value is valid or
false otherwise. Returning
false causes an exception to be thrown, cancelling the entire process.
| If you can't figure out where a given dependency property is getting its current value from, you can use the static |
When calling this method on the StatusBar instance from Listing 3.1 or 3.4 with the
Do not use this method in production code! Future versions of WPF could break assumptions you've made about the value calculation, plus treating a property value differently depending on its source goes against the way things are supposed to work in WPF applications.
|Digging Deeper: Clearing a Local Value|
| The earlier "Change Notification" section demonstrated the use of procedural code to change a |
What you likely want to do instead is clear the local value and let WPF set the value from the relevant provider with the next-highest precedence. Fortunately,
Note that the trigger on the