- WPF Resources Introduction
- WPF Resources Introduction Part 2
- WPF Resources Introduction Part 3
- WPF Assembly 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.
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.
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:
Conclusion
The last way, SetResourceReference, is the best way to do it.