XTab's Blog

Ged Mead's Blog at vbCity

This blog hosted by:
http://blogs.vbcity.com      
  Home :: Syndication  :: Login

AprMay 2008Jun
SMTWTFS
27282930123
45678910
11121314151617
18192021222324
25262728293031
1234567

Archives

Topics

Ramblings

VB.NET

Styles in WPF (2)- Styles, Resources and ResourceDictionaries 

Introduction

 In the first part of this article, we looked at a simple style that was created and applied to a set of Buttons. Each button has the same Background, Foreground, MinWidth, MinHeight, Margin and Padding. The resulting display looked like this:

  Original Five Buttons in a WrapPanel

 In point of fact, the amount of code reduction in that example was small. That's because the example uses only five buttons. But of course if the project had, say, 50, 100 or 200 buttons all using the same Style then the saving would be much greater.

 That leads me nicely into something I need to cover regarding accessibility of styles. The one I've used for the buttons is rather tightly locked down. Currently its scope is limited to that one particular WrapPanel.

 Here is the original code:

Code Copy
<WrapPanel x:Name="ButtonPanel" Background="Gainsboro">

<
WrapPanel.Resources>
<Style x:Key="BlackButton" >
<Setter Property="Button.Background" Value="Black" />
<
Setter Property="Button.Foreground" Value="White" />
<
Setter Property="Button.Margin" Value="12,3,12,3" />
<
Setter Property="Button.Padding" Value="3"  />
<
Setter Property="Button.MinWidth" Value="75" />
<
Setter Property="Button.MinHeight" Value="34" />
</Style>
</WrapPanel.Resources>

<
Button Style="{StaticResource BlackButton}">Open Button</Button>
<
Button Style="{StaticResource BlackButton}">Close Button</Button>
<
Button Style="{StaticResource BlackButton}">StartButton</Button>
<
Button Style="{StaticResource BlackButton}">Pause Button</Button>
<
Button Style="{StaticResource BlackButton}">StopButton</Button>
</
WrapPanel>

 A minor tweak that saves repetition is to assign the type of control to the TargetType. In this case of course the TargetType would be Button. It would then not be necessary to fully qualify the control name, as we have done (e.g. Button.Background, Button.Foreground, etc).

 The alternative code would be:

Code Copy
<Style x:Key="BlackButton" TargetType="{x:Type Button}">
<Setter Property="Background" Value="Black" />
<
Setter Property="Foreground" Value="White" />
<
Setter Property="Margin" Value="12,3,12,3" />
<
Setter Property="Padding" Value="3"  />
<
Setter Property="MinWidth" Value="75" />
<
Setter Property="MinHeight" Value="34" />
</Style>

 Note also that you can assign the more generic type of "Control" to the TargetType, i.e.:

     TargetType="{x:Type Control}" .

The style will then be available to all controls - any irrelevant properties being ignored.

Window Resources

 Let's start with where we might want to place that Style so that we can widen its scope. If those five buttons in the WrapPanel are the only ones we want to style in that way in this application then the code can happily be left as-is. However if we maybe want to use that button style elsewhere in the same Window, then all you have to do is cut and paste the Style out of the WrapPanel Resources and into the Window Resources:

Code Copy
<Window.Resources>
<Style x:Key="BlackButton" >
<Setter Property="Button.Background" Value="Black" />
<
Setter Property="Button.Foreground" Value="White" />
<
Setter Property="Button.Margin" Value="12,3,12,3" />
<
Setter Property="Button.Padding" Value="3"  />
<
Setter Property="Button.MinWidth" Value="75" />
<
Setter Property="Button.MinHeight" Value="34" />
</Style>
</Window.Resources>

<WrapPanel x:Name="ButtonPanel" Background="Gainsboro">
<Button Style="{StaticResource BlackButton}">Open Button</Button>
<
Button Style="{StaticResource BlackButton}">Close Button</Button>
<
Button Style="{StaticResource BlackButton}">StartButton</Button>
<
Button Style="{StaticResource BlackButton}">Pause Button</Button>
<
Button Style="{StaticResource BlackButton}">StopButton</Button>
</
WrapPanel>

 The Style will also be available for any other Button in that Window.

Application-wide Resources
 Moving further up the hierarchy, if the Style is to be used in more than one file across the project then the next place to consider is the Application.xaml file. This file is automatically created for you when you set up a new project. The only change needed from the previous example is the obvious one of changing the "< Window.Resources >" to "< Application.Resources >" when you cut and paste it from the Window xaml file to Application.xaml.

  If you omit the Key from the Style then that particular style becomes the default style for all buttons in the application. (The "key", you may remember from earlier blogs, represents the name of this style and you can use it to identify exactly which style you want to apply to individual controls).
This blanket coverage isn't set in tablets of stone, though. If you want to override the default style with another one of your choice then you simply assign the style name as in previous examples.

Code Copy
<!-- The first button uses the default style from Application.xaml-->
<
Button >Open Button</Button>
<!-- The next button uses a different Style -->

<
Button Style="{StaticResource GirlieButton}">Close Button</Button>
<!-- The remaining buttons use the default style from Application.xaml-->
<Button>StartButton</Button>
<
Button>Pause Button</Button>
<
Button>StopButton</Button>

 and you get something like this:

 For completeness (although I don't think you'll be needing it any time soon!), here's the Style code (which I placed in Window.Resources):

Code Copy
<Style x:Key="GirlieButton" TargetType="{x:Type Button}">
<Setter Property="Background" Value="Pink" />
<
Setter Property="Foreground" Value="Black" />
<
Setter Property="Margin" Value="12,3,12,3" />
<
Setter Property="Padding" Value="3"  />
<
Setter Property="MinWidth" Value="75" />
<
Setter Property="MinHeight" Value="34" />
</Style>

 There is however an alternative to pasting the Styles directly into Application.xaml and some people do prefer to take this route. That is to create one or more ResourceDictionaries and to place the dictionary or dictionaries in the Application's Resources markup. If for no better reason, this approach is worth considering because it keep the Styles neatly compartmentalized and also makes it very easy to lift a "Style File" ResourceDictionary from one project and reuse it in another one. It also reduces clutter in Application.xaml.


Resource Dictionary
It's simple to add a new ResourceDictionary to the project. Select "Project" from the top line menu and you will be able to select "Add Resource Dictionary" from the context menu that appears:

 Choose a name for it - I used "ButtonStyles" and add it to the project. The skeleton code in the xaml file looks like this:

Code Copy
<ResourceDictionary xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
    xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml">

</
ResourceDictionary>

 Once again, you can Cut and Paste the Style from wherever it currently sits (WrapPanel.Resources, Window.Resources or Application.Resources and paste it into the ResourceDictionary file. At his point, or in fact at any time in the future you can add further styles to this ResourceDictionary. This is a plus. Even better, if you subsequently decide that you want all the text on these buttons to be Yellow instead of White, then you only have to make the change in one place (the Style in the ResourceDictionary) and it will automatically be propagated throughout the application. If you're familiar with CSS you'll see the similarities.

 There is one more task needed to make the ResourceDictionary(ies) universally available. You have to place it or them inside a MergedDictionaries collection ... yep, even if there is only one of them! This code in the Application.xaml file will do the trick:

Code Copy
  <Application.Resources>
   <
ResourceDictionary>
<ResourceDictionary.MergedDictionaries>
<ResourceDictionary Source="ButtonStyles.xaml"/>
</ResourceDictionary.MergedDictionaries>
  </ResourceDictionary>
</
Application.Resources>

 

 And of course if you do happen to have more than one ResourceDictionary then you just add them inside the MergedDictionaries collection tags:

Code Copy
<ResourceDictionary.MergedDictionaries>
<ResourceDictionary Source="ButtonStyles.xaml"/>
<
ResourceDictionary Source="Dictionary2.xaml"/>
</ResourceDictionary.MergedDictionaries>

Just adding as many as you need as time goes on.

 Although this part hasn't covered much in the way of the Styles themselves, I hope the explanation of where to place the Styles for the scope you require and how to access those Styles is helpful to you. Initially I found the syntax for getting the application to find the styles in ResourceDictionaries a bit difficult to grasp, so I hope that this too is useful for you. In the next Part I will dig deeper into some more things you can include in Styles.

posted on Monday, September 10, 2007 11:17 AM

Feedback

# Stretching The Envelope - WPF Control Templates 10/1/2007 3:02 AM XTab's Blog


Post Feedback

Title:
Name:
Url:
Comments: 
Protected by Clearscreen.SharpHIPEnter the code you see: