WPF Resources Introduction Part 3


This entry is part 3 of 4 in the series WPF Resources

This is a continuation of Resources Introduction Part 2, where we were discussing XAML Resources from the book Illustrated WPF. Instead of defining the gradient brush in each button, a better strategy would be to define it once as a resource and store it higher up in the element tree—say, in the Window object. You can then retrieve it in the buttons. You can even and set the Backgrounds of the TextBlock and the StackPanel to the same resource, as shown in the following markup:

<Window x:Class="ResourcesXAML2.MainWindow"
        xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
        xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
        xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
        xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
        xmlns:local="clr-namespace:ResourcesXAML2"
        mc:Ignorable="d"
        Title="Resources XAML 2" Height="250" Width="325">
    <Window.Resources>
        <LinearGradientBrush x:Key="gradBrush" StartPoint="0,0" EndPoint="1,1">
            <GradientStop Color="White" Offset="0" />
            <GradientStop Color="Pink" Offset="1"/>
        </LinearGradientBrush> 
    </Window.Resources>
    <StackPanel  Background="{StaticResource gradBrush}" Name="sp">
        <TextBlock FontFamily="Arial Black" Margin="7"
            Background="{StaticResource gradBrush}"> 
                Some Buttons
        </TextBlock>
        <Button Height="40" Name="btn1" FontWeight="Bold" Background="{StaticResource gradBrush}">
            Button 1
        </Button>
        <Button Height="40" Name="btn2" FontWeight="Bold" Background="{StaticResource gradBrush}">
            Button 2
        </Button>
    </StackPanel>
</Window>

The name of our resource is granBrush. Here is what the program looks like.

ResourcesXAMLWindow

Static Resources and Dynamic Resources

When you assign a resource reference to a property, it’s assigned as either a StaticResource or a DynamicResource. In spite of the nomenclature, it’s not the resources themselves that are either static or dynamic; the same resource can be used as a StaticResource when assigned to one property and as a DynamicResource when assigned to another. The difference is in whether the reference in the ResourceDictionary is monitored for changes, which are then passed along to the property referencing the resource.

Dynamic Resources

With a DynamicResource, if the resource in the library changes, the property holding the old reference is updated automatically, under the covers.

When a StaticResource is read from the ResourceDictionary, its reference is assigned to the property once. If the reference in the resource library changes, the change doesn’t propagate to the property holding the original reference.

For example, suppose we use the markup from the previous example and make the following two changes:
(1) Of the four StaticResource markup extensions, let’s change three of them to DynamicResource but leave btn1 using a StaticResource.
(2) Add another button below the others, labeled Change, and give it an event handler that assigns a new Brush to the gradBrush resource.

Here is what the program looks like after the Change to Silver button is clicked.

ResourcesXAML3

After the update, the DynamicResource properties are referencing a new Brush, while the StaticResource property still references the original Brush.

Set Resource Reference

To set a DynamicResource in the code-behind, use the SetResourceReference method, as shown in the following code. Like FindResource, SetResourceReference searches up the element tree to find the resource with the given key. Suppose you have a button called myButton. The code-behind would look like this, assuming that you already has a resource defined as gradBrush.

myButton.SetResourceReference(BackgroundProperty, "gradBrush" );

The XAML markup, the C# code and the program is shown below.

<Window x:Class="Resources4.MainWindow"
        xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
        xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
        xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
        xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
        xmlns:local="clr-namespace:Resources4"
        mc:Ignorable="d"
        Title="Resources4" Height="200" Width="325">
    <Window.Resources>
        <LinearGradientBrush x:Key="gradBrush" StartPoint="0,0" EndPoint="1,1">
            <GradientStop Color="White" Offset="0" />
            <GradientStop Color="LightGreen" Offset="1"/>
        </LinearGradientBrush>
    </Window.Resources>
    <StackPanel Name="sp">
        <Button x:Name="btn1" Content="Button 1"/>
        <Button x:Name="btn2" Content="Button 2"/>
        <Button x:Name="btn3" Content="Button 3"/>
        <Button x:Name="btn4" Content="Button 4"/>
        <Button x:Name="btn5" Content="Button 5"/>
        <Button x:Name="btn6" Content="Button 6"/>
    </StackPanel>
</Window>

Here is the code behind:

using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using System.Windows;
using System.Windows.Controls;
using System.Windows.Data;
using System.Windows.Documents;
using System.Windows.Input;
using System.Windows.Media;
using System.Windows.Media.Imaging;
using System.Windows.Navigation;
using System.Windows.Shapes;
namespace Resources4
{
    /// <summary>
    /// Interaction logic for MainWindow.xaml
    /// </summary>
    public partial class MainWindow : Window
    {
        public MainWindow()
        {
            InitializeComponent();
            // create a solid colour brush with a color using Red Green Blue values
            SolidColorBrush scb = new SolidColorBrush(Color.FromRgb(50,255,50)) ;
            // add two resources
            sp.Resources.Add("myFavColor", scb);
            sp.Resources.Add("background", Brushes.Aqua);
            // btn1 uses default background, so Background not set here
            btn2.Background = (Brush)sp.Resources["background"];
            btn3.Background = (Brush)btn3.FindResource("background");
            btn4.SetResourceReference(Button.BackgroundProperty, "background");
            btn5.SetResourceReference(Button.BackgroundProperty, "myFavColor");
            btn6.SetResourceReference(Button.BackgroundProperty, "gradBrush");
        }
    }
}

Here is what the program looks like:

Resources4

Conclusion

The last way, SetResourceReference, is the best way to do it.

Series Navigation<< WPF Resources Introduction Part 2WPF Assembly Resources >>