#221 – Changing a Brush at Run-Time

You can change aspects of a Brush, such as its color, at run-time and any objects that use that brush will automatically be redrawn.

Let’s say that we have several controls in a window that make use of a SolidColorBrush:

		<SolidColorBrush x:Key="magicBrush" Color="Red"/>

		<Button Content="Don't Push Me" Background="{StaticResource magicBrush}" Width="120" Margin="10"/>
		<Label Content="Pull my finger!" Foreground="{StaticResource magicBrush}" HorizontalAlignment="Center"/>
		<Ellipse Height="100" Width="200" Fill="{StaticResource magicBrush}" Margin="10"/>


Now assume that we change the Color property of the brush at run-time:

    SolidColorBrush magicBrush = (SolidColorBrush)this.Resources["magicBrush"];
    magicBrush.Color = Colors.Purple;

When you do this, you’ll notice that the color in all of the controls changes as soon as this code executes.

All of the controls update immediately because SolidColorBrush derives from Freezable, which supports the Changed event.  The Changed event fires when the color changes and the controls handle that event and redraw themselves.


#174 – Predefined Brushes Are Already Frozen

All of the brushes in the predefined Brushes collection are already in a frozen state, meaning that they are read-only.  Being frozen means that they will perform more efficiently when using them to render graphical objects, since WPF doesn’t need to worry about notifying consumers of the brush when the brush changes.

Here’s an example, where we have two different labels, one painted with a brush created in XAML and one painted with a brush from the Brushes collection.

        <SolidColorBrush x:Key="tealBrush" Color="Teal"/>
        <Label Name="lblWithTealBrush" Content="I use a SolidColorBrush created in Window.Resources" Foreground="{StaticResource tealBrush}"/>
        <Label Name="lblWithRedBrush" Content="I use Brushes.Red">
                <x:Static Member="Brushes.Red"/>
        <Button Content="Click Me" Width="100" Click="btnTest_Click"/>

We can add code to check the frozen state of these two different brushes.

        private void btnTest_Click(object sender, RoutedEventArgs e)
            SolidColorBrush tealBrush = (SolidColorBrush)lblWithTealBrush.Foreground;
            bool frozen = tealBrush.IsFrozen;    // frozen = false

            SolidColorBrush redBrush = (SolidColorBrush)lblWithRedBrush.Foreground;
            frozen = redBrush.IsFrozen;          // frozen = true

#173 – You Can Put Freezable Objects Into a Read-Only State

The idea of an object deriving from Freezable is that it normally is in a read/write state, but can be explicitly put into a read-only state using the Freeze method.  A frozen object can be used more efficiently in WPF because it doesn’t need to notify consumers of the object that its value has changed.

Graphical objects in WPF like brushes and 3D geometries derive from Freezable.  Initially unfrozen, a change to one of these objects results in consumers of the objects being notified of the change.

If you have an object deriving from Freezable that you don’t plan to change, you can make the object read-only using the Freeze method.

            // Freeze this object, making it read-only (since we don't plan on changing it)
            if (theBrush.CanFreeze)

After freezing the object, if you try modifying it, you’ll get an InvalidOperationException.  But WPF will be more efficient in its use of the object.

#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