Friday, October 7, 2011

WPF Resources


WPF resource system allows you to keep useful objects around you so you can reuse easily. There are multiple ways to define Resources in WPF. In this post I will explain all the ways where we can define and use resources. Resource element defines a resource dictionary and dictionary requires every item to have key, so we must provide key to every resource declared inside resource dictionary.

Declaring resource inside element’s resources property -

You can declare resources which are going to be used inside your current window those resources can be declared inside Window.Resources element. In fact almost every resource in WPF has resources property so you can set anywhere you want. But the resources are accessible to the element and its child elements. Resources declared at top element (root level element) can be accessible to every element in window. In below example I have declared resources in window.resources element so every elements of window will have access those resources.

<Window x:Class="WpfApplication1.WPFResourcesDemo"
    xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
    xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
    Title="WPF Resources" Height="100" Width="300">
<Window.Resources>
    <LinearGradientBrush x:Key="linearGradientforButton">
        <GradientStop Color="Blue" Offset="0"/>
        <GradientStop Color="White" Offset="0.5"/>
        <GradientStop Color="Cyan" Offset="1"/>
    </LinearGradientBrush>
    <Style TargetType="Button" x:Key="ButtonStyle">
        <Setter Property="Width" Value="150" />
        <Setter Property="Height" Value="40" />
        <Setter Property="HorizontalAlignment" Value="Center" />
        <Setter Property="VerticalAlignment" Value="Top" />
        <Setter Property="Margin" Value="10" />
    </Style>
</Window.Resources>
<Grid>
    <Button Name="MyButton"
            Content="Click Me!"
            Background="{StaticResource linearGradientforButton}"
            Style="{StaticResource ButtonStyle}" />
</Grid>
</Window>



In above example, two resources are declared and both are used by one button. If you have multiple buttons in the same window, all the buttons will have access to the resources defined in window’s resources element. All the resource must be uniquely identified by x:key name inside resource dictionary. Similarly element can access those using StaticResource markup extension.

In WPF logical tree, almost every control has resource dictionaries. When any control uses resource, WPF look upward through the tree until it finds an object defined in resource with given key. In above example, Button’s background and style property uses resource from resource dictionary. So WPF will look upwards and it will find resource declared in window’s resource dictionary.

Declaring Resources in App.xaml - 

As shown in above example, if control uses resource then WPF look upwards till root object e.g. window but if the resource is not declared at root level then it will look in Application.Resources element of App.xaml file. The resources are declared in app.xaml file will be accessible to all windows inside application. So when resources are used by multiple windows, app.xaml file will be the best suitable place to declare those resources.


Let’s have a look on below code.

<Window x:Class="WpfApplication1.WPFResourcesDemo"
    xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
    xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
    Title="WPF Resources" Height="100" Width="300">
<Grid>
    <Button Name="MyButton"
        Content="Click Me!"
        Background="{StaticResource linearGradientforButton}"
        Style="{StaticResource ButtonStyle}" />
</Grid>
</Window>

app.xaml

<Application x:Class="WpfApplication1.App"
             xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
             xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
             StartupUri="WPFResourcesDemo.xaml">
    <Application.Resources>
        <LinearGradientBrush x:Key="linearGradientforButton">
            <GradientStop Color="Blue" Offset="0"/>
            <GradientStop Color="White" Offset="0.5"/>
            <GradientStop Color="Cyan" Offset="1"/>
        </LinearGradientBrush>
        <Style TargetType="Button" x:Key="ButtonStyle">
            <Setter Property="Width" Value="150" />
            <Setter Property="Height" Value="40" />
            <Setter Property="HorizontalAlignment" Value="Center" />
            <Setter Property="VerticalAlignment" Value="Top" />
            <Setter Property="Margin" Value="10" />
        </Style>
    </Application.Resources>
</Application>

The output of this code will be the same as first example. In this example resources are declared in Application.Resources element of App.XAML file


Declaring resources in separate Resource Dictionary -

WPF allows you to keep your all the resources at single place called resource dictionary file. Resource dictionary file has root element called ResourceDictionary. If your application has lots of resources and you want declare those resources inside app.xaml the file will be too large and difficult to manage and also it is not good practice to place so many resources inside app.xaml. In this case you should go for separate file called ResourceDictionary. You should place different resources in multiple resources file and merge it in window. You can create multiple resource dictionary files and merge those files inside your main window. Let’s have a look on below code.

ResourceDictionary.Xaml

<ResourceDictionary xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
                    xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml">
    <LinearGradientBrush x:Key="linearGradientforButton">
        <GradientStop Color="Blue" Offset="0"/>
        <GradientStop Color="White" Offset="0.5"/>
        <GradientStop Color="Cyan" Offset="1"/>
    </LinearGradientBrush>
    <Style TargetType="Button" x:Key="ButtonStyle">
        <Setter Property="Width" Value="150" />
        <Setter Property="Height" Value="40" />
        <Setter Property="HorizontalAlignment" Value="Center" />
        <Setter Property="VerticalAlignment" Value="Top" />
        <Setter Property="Margin" Value="10" />
    </Style>
</ResourceDictionary>

MainWindow.Xaml

<Window x:Class="WpfApplication1.WPFResourcesDemo"
    xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
    xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
    Title="WPF Resources" Height="100" Width="300">
    <Window.Resources>
        <ResourceDictionary>
            <ResourceDictionary.MergedDictionaries>
                <ResourceDictionary Source="MyResourceDictionary.xaml" />
            </ResourceDictionary.MergedDictionaries>
        </ResourceDictionary>
    </Window.Resources>
<Grid>
    <Button Name="MyButton"
        Content="Click Me!"
        Background="{StaticResource linearGradientforButton}"
        Style="{StaticResource ButtonStyle}" />
</Grid>
</Window>

The output of this example is same as above two examples. In this example resources are placed inside separate ResourceDictionary file and in MainWindow resource dictionary merged in Window.Resources element.

Accessing Resources from code - 

WPF resources can also be created or accessed using code. Inside code we need to find resource by key name using TryFindResoruce Method or FindResource method. Both methods used to find resources from resource dictionary the only difference is FindResource method will throw an exception if resource not found while TryFindResource Method will return null. Let’s have a look on below code.

private void MyButton_Click(object sender, RoutedEventArgs e)
{
    MyButton.Background = (Brush)TryFindResource("linearGradientforButton");
}

In above code snippet, TryFindResource method will try to find “linearGradientforButton” resource from dictionary if found assign to background property and if not found then assign null to background property.


Hope you liked this article on WPF Resources. Please feel free to write feedback/comments in comment section below.


See also –

6 comments: