Dependency Properties – Precedence

Today we wrap up dependency properties by talking about one of the most important, though typically invisible aspects: DP precedence order. This is critical because dependency properties, by their nature, are designed to have their final value set from more than one influence (e.g., resources, data binding, animation, etc.)

The rule is rigid, sensible and straight forward…

Animation uber alles.

If there is an animation affecting the value, that will take precedence over all other values

Local values over everything but Animation

In the absence of an animation, use the local value to override any other values

Templates/Styles if no animation or local values

If there is no animation or local value, use the value from the template, and if there is no template then from the style.

When all else fails, use the default

If none of the above apply, use the default value for that type.

The Default Value

It is the last rule that demands that every type have a default look, and it is because of that rule that you crated generic.xaml – so that if your custom control has a value that is not controlled by an animation, a local value, a template or a style, the Dependency Property System will turn to the default values in generic.xaml and use those.

Our First Application

With this, we're ready to examine the code to our first application.  As you may remember, we have three projects in one solution.  In CustomControl.cs we declare the visual logic of our control and we will, eventually declare the logic (event handlers, etc.) as well. For now, the listing is quite simple:

   1: using System.Windows.Controls;
   2:  
   3: namespace ClassLibrary
   4: {
   5:    public class CustomControl : Control 
   6:    {
   7:       public CustomControl()
   8:       {
   9:          DefaultStyleKey = typeof( CustomControl );
  10:       }
  11:    }
  12: }

The simplest logic you can add to get the default style to show. The default style, as you remember is in the file generic.xaml which in turn is in the Themes folder,

   1: <ResourceDictionary
   2:     xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation" 
   3:     xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml" 
   4:     xmlns:controls="clr-namespace:ClassLibrary" 
   5:     xmlns:vsm="clr-namespace:System.Windows;assembly=System.Windows" 
   6:     xmlns:d="http://schemas.microsoft.com/expression/blend/2008" 
   7:     xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006" 
   8:     mc:Ignorable="d">
   9:     <Style TargetType="controls:CustomControl">
  10:         <Setter Property="Template" >
  11:             <Setter.Value>
  12:                 <ControlTemplate TargetType="controls:CustomControl">
  13:                     <Grid x:Name="LayoutRoot">
  14:                         <Ellipse x:Name="Core" 
  15:                             Width="75" Height="75" 
  16:                             Stroke="Blue" StrokeThickness="2" >
  17:                             <Ellipse.Fill>
  18:                                 <RadialGradientBrush>
  19:                                     <GradientStop Color="#FFE0E1F0" Offset="0.004"/>
  20:                                     <GradientStop Color="#FF8080B1" Offset="1"/>
  21:                                     <GradientStop Color="#FF05052B" Offset="0.911"/>
  22:                                 </RadialGradientBrush>
  23:                             </Ellipse.Fill>
  24:                         </Ellipse>
  25:                     </Grid>
  26:                 </ControlTemplate>
  27:             </Setter.Value>
  28:         </Setter>
  29:     </Style>
  30: </ResourceDictionary>

Remember to set the BuildAction property of this file to Resource

SetAsResource

Page.xaml will create an instance of your custom control and an instance of a TextBlock

   1: <UserControl x:Class="SkinnableCustomControl.Page"
   2:     xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation" 
   3:     xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml" 
   4:     xmlns:Controls="clr-namespace:ClassLibrary;assembly=ClassLibrary"              
   5:     Width="400" Height="300">
   6:     
   7:     <Grid x:Name="LayoutRoot" Background="White">
   8:         <Grid.RowDefinitions>
   9:             <RowDefinition Height=".7*" />
  10:             <RowDefinition Height=".3*" />
  11:         </Grid.RowDefinitions>
  12:         <Controls:CustomControl x:Name="CustomCtrl" Grid.Row="0" />
  13:         
  14:         <TextBlock Text="Skinnable Custom Control" 
  15:                    FontFamily="Georgia" FontSize="18" 
  16:                    HorizontalAlignment="Center" Grid.Row="1" />
  17:     </Grid>
  18: </UserControl>

When you run this, the custom control is drawn (along with the text block)

SkinnableCustomControlRunning

At the moment it doesn't respond to visual events such as mouse over, nor does it have any logic to handle clicks, but it does draw and it does have a default appearance. It exists (to a minimal degree) within the Parts and States model, and it is pretty straight forward from here to add the missing bits.

Next time.

 

-jesse

About Jesse Liberty

Jesse Liberty has three decades of experience writing and delivering software projects and is the author of 2 dozen books and a couple dozen online courses. His latest book, Building APIs with .NET will be released early in 2025. Liberty is a Senior SW Engineer for CNH and he was a Senior Technical Evangelist for Microsoft, a Distinguished Software Engineer for AT&T, a VP for Information Services for Citibank and a Software Architect for PBS. He is a Microsoft MVP.
This entry was posted in z Silverlight Archives. Bookmark the permalink.

One Response to Dependency Properties – Precedence

Comments are closed.