Recreating Simple Windows Forms in WPF and XAML (Part 3)
Submitted by smartyP on Sat, 07/12/2008 - 10:28Last time we covered how to break out colors from our XAML dialog into separate color definitions in the Page.Resources section of our XAML. After doing this the next question is something like "how do I break out the color, font size, font face, etc. from each of my textbox definitions", and "how can I break these styling definitions out to a separate file" - those are what we will cover in this part of the series.
After breaking out my colors last time my footer definition ended up something like this:
<!-- bottom panel (ok & cancel buttons) -->
<StackPanel DockPanel.Dock="Bottom" Orientation="Horizontal"
FlowDirection="RightToLeft" Height="32"
Background="{StaticResource footerFillBrush}">
<Button Width="72" TabIndex="45" Margin="2,2,2,2">Cancel</Button>
<Button Width="72" TabIndex="40" Margin="2,2,2,2">OK</Button>
</StackPanel>
It's cool that my background color isn't hard-coded now, but all the other styling elements are still hard-coded - that is where Style definitions come in. Style definitions basically allow you to define all the properties that should be set on an element in one spot. You can then assign the Style you created to a textbox, or a label, or any other UI element you might want to style. You give the Style a Key name just like you would a color definition and then tell the UI element to make use of that Style (there is another way to use styles across all items of a given type instead of specifying which one to use for every UI element - we will cover that towards the end of this article).
(click 'read more' to read the full article..)
<!-- style for bottom footer -->
<Style x:Key="footerPanelStyle" TargetType="{x:Type StackPanel}">
<Setter Property="Orientation" Value="Horizontal" />
<Setter Property="FlowDirection" Value="RightToLeft" />
<Setter Property="Height" Value="32" />
<Setter Property="Background" Value="{StaticResource footerFillBrush}" />
</Style>
Above is our new style definition which is placed inside our Page.Resources definition in our XAML just like our color brushes were in the last part of this series. You can see that all of the properties we were setting in the StackPanel itself have been moved into individual Setter definitions - we define what property will be set to what value. You can see in this Style definition that we are referencing our Brush definition inside of the Style itself - so that we can separate the colors from the styling just like before.
So now we just change the StackPanel to make reference to our new Style just like we did before for our color brushes:
<!-- bottom panel (ok & cancel buttons) -->
<StackPanel Style="{StaticResource footerPanelStyle}" DockPanel.Dock="Bottom">
<Button Width="72" TabIndex="45" Margin="2,2,2,2">Cancel</Button>
<Button Width="72" TabIndex="40" Margin="2,2,2,2">OK</Button>
</StackPanel>
There are at least 10-12 items in the original XAML dialog posting which could be broken into styles. Combine these new Style definitions with all the color brushes from the last part of this series and you will end up with a Resource definition just as long as the actual structural XAML, so at this point it only makes sense to break out these styles and colors into a separate styling XAML file.
Moving your Resource definitions to a standalone file is relatively simple. Just create a new XAML file and replace whatever is in it with the following:
<ResourceDictionary
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml" >
</ResourceDictionary>
Next just take everything in your Page.Resources section of your XAML file and move it into this file between the opening and closing ResourceDictionary tags. Here is a short example with our new footer Style in it:
<ResourceDictionary
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml" >
<!-- style for bottom footer -->
<Style x:Key="footerPanelStyle" TargetType="{x:Type StackPanel}">
<Setter Property="Orientation" Value="Horizontal" />
<Setter Property="FlowDirection" Value="RightToLeft" />
<Setter Property="Height" Value="32" />
<Setter Property="Background" Value="{StaticResource footerFillBrush}" />
</Style>
</ResourceDictionary>
Now we just have to tell our main XAML file to reference our new one containing the Resource definitions. This is done by telling it what XAML files to load as its ResourceDictionary. The files will be loaded in the order specified, so if any Styles of the same name are defined in multiple files, the last one loaded will be the Style used. Here is our original XAML dialog file referencing our new XAML ResourceDictionary inside of the Page.Resources tag we just cleared out:
<Page.Resources>
<ResourceDictionary>
<ResourceDictionary.MergedDictionaries>
<ResourceDictionary Source="C:\SmartyPantsCoding\DialogTry1_ExternalResourceDictionary.xaml"/>
</ResourceDictionary.MergedDictionaries>
</ResourceDictionary>
</Page.Resources>
You'll note that we are still using hardcoded paths here. This is partly because Kaxaml will always look in its own Program Files folder if we try to use a relative path, and partly because I don't want to change the reference to be a web reference or anything else since we are still editing it.
One last thing to note is how to make use of a Style across all items of a given type. If we have created a Style for our textboxes it doesn't make much sense to have to specify the style to use across every textbox. By not providing a Key name in the Style, and by setting the TargetType to textbox we can make it to where every textbox which doesn't specify a Style will make use of this style by default.
Here is our style as defined in our new external Resources XAML file:
<!-- textbox style -->
<Style TargetType="{x:Type TextBox}">
<Setter Property="Background" Value="{StaticResource textboxBackgroundColor}" />
<Setter Property="Margin" Value="2,2,2,2" />
</Style>
.. and here are a few of our textboxes from the main XAML file:
<!-- form fields -->
<TextBox Grid.Column="1" Grid.Row="0" TabIndex="10" />
<TextBox Grid.Column="1" Grid.Row="1" AcceptsReturn="True" TabIndex="15" />
So you can see that our TextBox entries don't even specify a Style to use, but they are using the Style defined in our Resources XAML file because it has no Key specified and it is explicitly setting the TargetType.
By now the dialog looks totally different, and the XAML behind it is totally different as well. There is plenty left to learn from this project, but now is a good point to provide an updated screenshot and the new XAML files - since none of our work so far has been to the MDI application form, only the updated XAML files from the dialog form are attached.
A simple dialog - after part 3
By now you should be thinking about how easy it would be to create different styling files to use without affecting the overall structure XAML file, all without affecting any code you might have attached to the structure as well. Next will be styling more complex items like buttons and seeing how to style each of the mouse over/click appearances.
Attachment | Size |
---|---|
DialogTry2.xaml | 5.13 KB |
DialogTry2_ExternalResourceDictionary.xaml | 6.43 KB |