#172 – Changes to a Brush Cascade to Consumers of the Brush

If you create a Brush object, in XAML or code, and use that Brush in some controls, any changes to the original Brush are automatically reflected in controls that use the brush.

For example, assume that we define a teal SolidColorBrush as a resource and use it to render a Label.

    <Window.Resources>
        <SolidColorBrush x:Key="tealBrush" Color="Teal"/>
    </Window.Resources>
    <StackPanel>
        <Label Content="I'm teal!" Foreground="{StaticResource tealBrush}"/>
    </StackPanel>

Now assume that we change the brush’s color at runtime:

            SolidColorBrush theBrush = (SolidColorBrush)this.Resources["tealBrush"];
            theBrush.Color = Colors.DarkMagenta;

You’ll see that the foreground color of the Label changes immediately, as soon as we change the color of the brush.

This change notification behavior is true not only of the Brush class, but of all other classes used in rendering WPF graphics.

Advertisements

#171 – Other Base Classes – Freezable and Animatable

We can add two other important base classes to our class hierarchy–Freezable and Animatable.

  • Freezable – Implements a “freezable” pattern, in that the object can provide a “frozen” read-only copy of itself.
  • Animatable – Derives from Freezable and adds the ability to animate properties

#170 – Functionality That The Base Element Classes Provide

The four main base element classes in WPF each provide slightly different functionality, above and beyond DependencyObject, which they all inherit from, directly or indirectly.

  • ContentElement adds (to DependencyObject)
    • Input events and commanding
    • Focus
    • Raise and respond to routed events
    • Animation support
  • FrameworkContentElement adds (to ContentElement)
    • Additional input elements (e.g. tooltips, context menus)
    • Storyboards
    • Data binding
    • Styles
    • Property value inheritance
  • UIElement adds (to DependencyObject)
    • via Visual
      • Hit testing
      • Clipping and coordinate transformations
      • Participation in visual tree via parent/child relationships
    • Layout behavior (measure/arrange)
    • Input events and commanding
    • Focus
    • Raise and respond to routed Events
    • Animation support
  • FrameworkElement adds (to UIElement)
    • Additional input elements (e.g. tooltips, context menus)
    • Storyboards
    • Data binding
    • Styles
    • Property value inheritance
    • Support for the logical tree

 

#169 – The Base Element Classes

There are four main classes that that serve as base classes for many of the other classes in WPF.  They also often serve as base classes for new custom classes that you write.

The four base element classes are:

  • ContentElement
  • FrameworkContentElement
  • UIElement
  • FrameworkElement

#168 – A More Complete Class Hierarchy

Post #27 presented a class hierarchy that shows the most common classes used in WPF.  Here is an updated view, with ContentElement and FrameworkContentElement added.  These two classes are sometimes used as base classes for creating new elements, so it’s important to know where they fit in the class hierarchy.

(Click on the image to see the diagram full-sized).

 

#167 – Implementing a Dependency Property That Is A Collection

When you create a custom dependency property that is based on a collection type, you need to define the default value of the property as a new instance of a collection, rather than as just a static value.

For example, we defined the Person.IQ dependency property, with a default value of 100, as follows:

internal static readonly DependencyPropertyKey IQPropertyKey =
    DependencyProperty.RegisterReadOnly("IQ", typeof(int), typeof(Person), new PropertyMetadata(100));

If we define a read-only Person.Friends property, whose type is List<Person>, the same call would look like this:

        internal static readonly DependencyPropertyKey FriendsPropertyKey =
            DependencyProperty.RegisterReadOnly("Friends", typeof(List<Person>), typeof(Person),
              new PropertyMetadata(new List<Person>()));      // Metadata constructor instantiates a new List