XML files are very handy for storing and display data that you might not want to keep in a database. It is wonderful choice for prototyping since you do not need to setup any database tables, connection strings and data objects. Instead you can send a complete project to a user that they can try out immediately without any setup at all. There are actually several methods you can use to display XML within a WPF application, let’s look at a few.
The XML Data
For the samples in this article, the XML data is a simple set of Product data. The XML file, called Product.xml, looks like the following:
<Products>
<Product>
<ProductId>1</ProductId>
<ProductName>Architecting ASP.NET Applications
eBook</ProductName>
<Price>19.95</Price>
</Product>
<Product>
<ProductId>2</ProductId>
<ProductName>Fundamentals of N-Tier eBook</ProductName>
<Price>19.95</Price>
</Product>
...
...
<Product>
<ProductId>3</ProductId>
<ProductName>Security for ASP.NET Developers
eBook</ProductName>
<Price>19.95</Price>
</Product>
</Products>
Using the XML Data Provider
The simplest method of display XML data is to use the XmlDataProvider object in XAML. You create an XmLDataProvider and set its Source property to the location of where the XML file is located. Consider the following XmlDataProvider created in a Window.Resources area.
<Window.Resources>
<XmlDataProvider x:Key="ProductData"
Source="/Product.xml"
XPath="Products/Product" />
</Window.Resources>
Notice that the Key is set to a unique identifier for this resource. You then specify the Source with where the XML file is located. Finally you specify the top level XPath query that will be used to get to the node level where you will be displaying data. If you use a ListBox on this Window you would specify the ItemsSource to be data bound to this StaticResource “ProductData”. You then reference the element name within the XML that you want to use to display in the ListBox. Since you have already specified “Products/Product” in the XPath attribute of the XmlDataProvider, the DisplayMemberPath can be just set to the element to display; in this case “ProductName”.
<ListBox
ItemsSource="{Binding
Source={StaticResource ProductData}}"
DisplayMemberPath="ProductName" />
Sorting using a CollectionViewSource
One additional nice feature you might want to add is the ability to sort the XML data. You can accomplish this complete in XAML by using a CollectionViewSource object. The CollectionViewSource object will take a source set of data from an XmlDataProvider (or any data provider for that matter) and you can then apply some additional elements to do things like sorting or grouping. For sorting data you will add SortDescriptions to the collection. Look at the XAML below.
<Window.Resources>
<XmlDataProvider x:Key="ProductData"
Source="/Product.xml"
XPath="Products/Product" />
<CollectionViewSource x:Key="collProducts"
Source="{StaticResource ProductData}">
<CollectionViewSource.SortDescriptions>
<scm:SortDescription PropertyName="ProductName"
Direction="Ascending" />
</CollectionViewSource.SortDescriptions>
</CollectionViewSource>
</Window.Resources>
You can see that you added a CollectionViewSource.SortDescriptions element within the <CollectionViewSource> element. This element allows you to add one or many sort description objects. The SortDescription object you add comes from the System.ComponentModel namespace within the WindowsBase assembly. So, you will need to add a XAML namespace at the top of your window that looks like the following:
xmlns:scm=
"clr-namespace:System.ComponentModel;assembly=WindowsBase"
You can give it any “name” you want, I chose “scm”, so that is what I used when adding the SortDescription element with the PropertyName set to “ProductName” and the Direction set to “Ascending”. Setting these two properties is what will then sort the data in the CollectionViewSource by the ProductName element in the XML file. Notice that the Source property of the CollectionViewSource is set to the XmlDataProvider object. So the CollectionViewSource creates a collection of the XML data and applies to the sort description to create a new “view” of the original data. You now use the CollectionViewSource as the ItemsSource property of the List Box as shown below.
<ListBox
ItemsSource="{Binding Source={StaticResource collProducts}}"
DisplayMemberPath="ProductName" />
Using LINQ to XML
Another method you can use to display XML data in a WPF application is to use LINQ to XML. Sometimes LINQ to XML might be necessary if you have a more complicated XML file, or if you wish to filter the data in a special way, or just want to read a few elements instead of every element.
To use LINQ to XML you must set the Build Action property of the Product.xml file to “Content” and the Copy to Output Directory to “Copy if newer”. Instead of using an XmlDataProvider this time load the data writing some C# or VB code. In the ListBox you set the ItemsSource to “{Binding}”. This tells the list box that the data will be supplied at runtime.
<ListBox Margin="10"
ItemsSource="{Binding}"
Name="lstProducts" />
In the Windows Loaded event you will call the ProductsLoad procedure which uses LINQ to XML to create a collection of XElement objects.
private void Window_Loaded(object sender, RoutedEventArgs e)
{
ProductsLoad();
}
To use LINQ to XML you will need to import a couple of namespaces.
using System.Linq;
using System.Xml.Linq;
Now, in the ProductsLoad procedure you use the Load method of the XElement class to load the XML file. Then you write a normal LINQ query to iterate over the “Product” Descendants in the XML file. In this query you will also use an order by clause to order each element by ProductName, then select the ProductName. You could select more elements if you want, but since all you are doing is displaying ProductName in the ListBox, let’s just grab this one piece of data from the XML file.
private void ProductsLoad()
{
var xElem = XElement.Load(@"Product.xml");
var products = from prod in xElem.Descendants("Product")
orderby prod.Element("ProductName").Value
select prod.Element("ProductName").Value;
lstProducts.DataContext = products;
}
Summary
XML files are a great way to display data in WPF applications. I find XML files to be especially useful for prototyping as I find creating XML files much quicker than creating database tables and hooking up to those database tables from WPF. You have a lot of different methods to retrieve the XML data. In this article I showed you how to display the data using the XmlDataProvider, a CollectionViewSource and LINQ to XML.
NOTE: You can download the complete sample code at my website. http://www.pdsa.com/downloads. Choose Tips & Tricks, then "Use XML Files in WPF" from the drop-down.
Good Luck with your Coding,
Paul Sheriff
** SPECIAL OFFER FOR MY BLOG READERS **
Visit http://www.pdsa.com/Event/Blog for a free eBook on "Fundamentals of N-Tier".
We are developing a WPF application for a client where they want to be able to use the SizeToContent=”WidthAndHeight” attribute on the window. This attribute is great because it allows WPF to size the window to the size of the controls on the window. This is especially important as they need the labels to grow and shrink when they localize the labels for English, Spanish and German. Once the initial size is set by WPF, they want that initial size to be the minimum height and minimum width for that window. As it turns out, this is very easy to accomplish in WPF.
The Form
Figure 1 shows a sample form that uses a <Grid> control and row and columns for the labels, text boxes and buttons. Using a grid control allows your controls to grow and shrink as you re-size the window.

Figure 1: Setting the initial MinWidth and MinHeight properties
Take a look at the XAML for this window.
<Window x:Class="SetInitialMinWidthHeight.winMain"
x:Name="winTest"
xmlns="http://schemas.microsoft.com/winfx/2006
/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
Title="Set Initial MinWidth/MinHeight"
WindowStartupLocation="CenterScreen"
MinWidth="{Binding ElementName=winTest,
Path=InitialMinWidth}"
MinHeight="{Binding ElementName=winTest,
Path=InitialMinHeight}"
SizeToContent="WidthAndHeight"
Loaded="Window_Loaded">
<Window.Resources>
<!-- SOME RESOURCES HERE -->
</Window.Resources>
<Grid Margin="10">
<Grid.RowDefinitions>
<!-- ROW DEFINITIONS HERE -->
</Grid.RowDefinitions>
<Grid.ColumnDefinitions>
<!-- COLUMN DEFINITIONS HERE -->
</Grid.ColumnDefinitions>
<TextBlock Grid.Row="0"
Grid.Column="0"
Text="First Name" />
<TextBox Grid.Row="0"
Grid.Column="1"
x:Name="txtFirstName" />
<TextBlock Grid.Row="1"
Grid.Column="0"
Text="Last Name" />
<TextBox Grid.Row="1"
Grid.Column="1"
x:Name="txtLastName" />
<Button Grid.Row="2"
Grid.Column="1"
Content="Submit" />
</Grid>
</Window>
Most of this window is pretty normal grid layout XAML code, but take a look at the MinWidth, MinHeight and SizeToContent properties. Notice that the SizeToContent property is set to WidthAndHeight. This allows the window to size itself based on how much room the child controls take up. Take a look at the binding used for the MinWidth and MinHeight properties. Each of these two properties are binding to Dependency properties that have been created on the window itself. Notice that the binding refers to the “winTest”, which has been set as the x:Name of the Window.
The Dependency Properties
In order to data-bind from XAML to a property on your form you need to create a Dependency Property. Both the “InitialMinHeight” and “InitialMinWidth” properties that are being bound are dependency properties. You create dependency properties using the DependencyProperty.Register() static method. To create our InitialMinHeight property you first create a static DependencyProperty with the name InitialMinHeightProperty. Notice the “Property” suffix added at the end.
C#
protected static DependencyProperty InitialMinHeightProperty =
DependencyProperty.Register(
"InitialMinHeight", typeof(double), typeof(winMain));
protected static DependencyProperty InitialMinWidthProperty =
DependencyProperty.Register(
"InitialMinWidth", typeof(double), typeof(winMain));
VB
Protected Shared InitialMinHeightProperty As DependencyProperty _
= DependencyProperty.Register("InitialMinHeight", _
GetType(Double), GetType(winMain))
Protected Shared InitialMinWidthProperty As DependencyProperty _
= DependencyProperty.Register("InitialMinWidth", _
GetType(Double), GetType(winMain))
Once you have created these dependency properties, you now create normal properties. However, in the getter and setters you call the GetValue and SetValue methods that are part of the WPF Window class.
C#
protected double InitialMinHeight
{
get { return (Double)GetValue(InitialMinHeightProperty); }
set { SetValue(InitialMinHeightProperty, value); }
}
protected double InitialMinWidth
{
get { return (Double)GetValue(InitialMinWidthProperty); }
set { SetValue(InitialMinWidthProperty, value); }
}
VB
Protected Property InitialMinHeight() As Double
Get
Return DirectCast(GetValue(InitialMinHeightProperty), _
Double)
End Get
Set(ByVal value As Double)
SetValue(InitialMinHeightProperty, value)
End Set
End Property
Protected Property InitialMinWidth() As Double
Get
Return DirectCast(GetValue(InitialMinWidthProperty), _
Double)
End Get
Set(ByVal value As Double)
SetValue(InitialMinWidthProperty, value)
End Set
End Property
Now that you have created these properties, you can now set them during the Loaded event procedure.
C#
private void Window_Loaded(object sender, RoutedEventArgs e)
{
// Set dependency properties after form's height/width
// has been set initially
InitialMinWidth = this.ActualWidth;
InitialMinHeight = this.ActualHeight;
}
VB
Private Sub Window_Loaded(ByVal sender As Object, _
ByVal e As RoutedEventArgs)
' Set dependency properties after form's width/height
' has been set initially
InitialMinWidth = Me.ActualWidth
InitialMinHeight = Me.ActualHeight
End Sub
The ActualWidth and ActualHeight properties are set with whatever the values are that have been determined by WPF. You retrieve these values and put them into the dependency properties. The dependency properties allow the values to be updated and put into the MinWidth and MinHeight property of the Window.
Summary
In this article you learned how to set an initial minimum width and height. Using dependency properties and data binding you can have a WPF window set its initial size using SizeToContent, save those settings, then set the MinWidth and MinHeight on the Window.
NOTE: You can download the complete sample code at my website. http://www.pdsa.com/downloads. Choose Tips & Tricks, then "WPF Set Initial Min Width and Height" from the drop-down.
Good Luck With Your Coding,
Paul Sheriff
** SPECIAL OFFER FOR MY BLOG READERS **
Visit http://www.pdsa.com/Event/Blog for a free eBook on "Fundamentals of N-Tier".
In my last blog post, I showed you how to use a Shape control, a Border control and a TextBlock to create rectangles, circles, ellipsis, and triangles with text in the middle of the shape. You also learned how to use a VisualBrush in a TextBlock to help you center the text as well. In this post, you will learn another technique for accomplishing the same task. This blog will show you how to use a Canvas, a Shape and a TextBlock. The reason for using a Canvas is to introduce you to using a Multi-Binding converter in WPF.
Position a Shape on a Canvas
As you may know, a Canvas control is used to position a canvas’ child controls at a specified point on the Canvas. You place a shape at a certain point by setting the attached properties “Canvas.Top” and “Canvas.Left” as shown in the following XAML.
<Canvas Name="cnvMain"
Width="80"
Height="80">
<Ellipse Canvas.Top="20"
Canvas.Left="40"
Width="40"
Height="40"
Fill="Gray" />
</Canvas>
In Figure 1 you can see that the Circle is positioned 20 points below the top of the Canvas and 40 points to the right of the canvas’ leftmost border.

Figure 1: Position the Circle at a specific point on a Canvas
Place a Shape within a Canvas
Most of the time, you want a shape to take up the same amount of width and height as the canvas. So, you can simply set the Width and Height properties of both the Canvas control and the Shape control to be exactly the same. Since the Shape control is the child within the Canvas, it will fill up the whole canvas. Note that you do not need to specify the Canvas.Top and Canvas.Left as the default for these is zero (0) for any child control placed in a Canvas.
<Canvas Name="cnvMain"
Width="80"
Height="80">
<Ellipse Width="80"
Height="80"
Fill="Gray" />
</Canvas>
Bind Ellipse Width and Height to Canvas
The problem with the above XAML is that if you wish to change the width and the height of the canvas and you want the shape to be the exact same height, you need to change four numbers. Instead of hard-coding the numbers on the Shape control, you can take advantage of the element-to-element binding features of WPF. Below is an example of binding the Width and Height of the Ellipsis to the Width and Height of the Canvas. The XAML below will produce the circle shown in Figure 2.
<Canvas Name="cnvMain"
Width="80"
Height="80">
<Ellipse Width="{Binding ElementName=cnvMain,
Path=ActualWidth}"
Height="{Binding ElementName=cnvMain,
Path=ActualHeight}"
Fill="Gray" />
</Canvas>
Figure 2: A circle bound to the same height and width as the Canvas on which it is placed.
Using a Multi-Binding Converter
Now that you have learned to place a Shape within a Canvas, you now need to put a TextBlock in the center of the Canvas so you can have words display in the middle of the Shape. To center a TextBlock in the middle of a Canvas you need to take the Width of the Canvas and subtract the Width of the TextBlock, then divide this by 2 to get the value for the Left property. You use the same calculation for the Height to get the Top property of where to position the TextBlock.
It would be really convenient if you could use an expression in a WPF binding since you could then perform this calculation, but you can’t. So, instead, you need to pass the width of the Canvas and the width of the TextBlock to some code you write, and also the height of the Canvas and TextBlock. This is where a multi-binding converter comes in very handy.
Consider the following XAML:
<Canvas Name="cnvMain"
Width="40"
Height="40">
<Rectangle Name="rectSize"
Fill="Blue"
Width="{Binding ElementName=cnvMain,
Path=ActualWidth}"
Height="{Binding ElementName=cnvMain,
Path=ActualHeight}"
Stroke="Black"
StrokeThickness="2" />
<TextBlock Name="tbSize"
Foreground="White"
Text="Test">
<Canvas.Left>
<MultiBinding
Converter="{StaticResource MidValue}">
<Binding ElementName="cnvMain"
Path="ActualWidth" />
<Binding ElementName="tbSize"
Path="ActualWidth" />
</MultiBinding>
</Canvas.Left>
<Canvas.Top>
<MultiBinding Converter="{StaticResource MidValue}">
<Binding ElementName="cnvMain"
Path="ActualHeight" />
<Binding ElementName="tbSize"
Path="ActualHeight" />
</MultiBinding>
</Canvas.Top>
</TextBlock>
</Canvas>
Notice the code in the above XAML that sets the <Canvas.Left> within the <TextBlock> control. This code, shown below, is responsible for passing data to our multi-binding converter.
<TextBlock ...>
<Canvas.Left>
<MultiBinding Converter="{StaticResource MidValue}">
<Binding ElementName="cnvMain"
Path="ActualWidth" />
<Binding ElementName="tbSize"
Path="ActualWidth" />
</MultiBinding>
</Canvas.Left>
</TextBlock>
Just like a normal binding sets one specific value, a <MultiBinding> allows you to pass more than one value to a converter class. Notice the “Converter={…}” attribute uses a StaticResource called Midvalue. This static resource is defined in the Window.Resources section of this window as follows:
<Window.Resources>
<src:MidpointValueConverter x:Key="MidValue" />
</Window.Resources>
The MidPointValueConverter class implements the IMultiValueConverter interface. This interface defines the Convert and ConvertBack methods. It is your job to write the code to take the multiple inputs that are passed to the “values” parameter to the Convert method and return a single value that can be used to set the Left property.
C#
using System;
using System.Globalization;
using System.Windows.Data;
public class MidpointValueConverter : IMultiValueConverter
{
#region Convert/ConvertBack Methods
public object Convert(object[] values, Type targetType,
object parameter, CultureInfo culture)
{
double extra = 0;
if (values == null || values.Length < 2)
{
throw new ArgumentException("The MidpointValueConverter
class requires 2 double values to be passed to it.
First pass the Total Overall Width, then the
Control Width to Center.", "values");
}
double totalMeasure = (double)values[0];
double controlMeasure = (double)values[1];
if (parameter != null)
extra = System.Convert.ToDouble(parameter);
return (object)(((totalMeasure - controlMeasure) / 2) + extra);
}
public object[] ConvertBack(object value, Type[] targetTypes,
object parameter, CultureInfo culture)
{
throw new NotImplementedException();
}
#endregion
}
Visual Basic
Imports System
Imports System.Globalization
Imports System.Windows.Data
Public Class MidpointValueConverter
Implements IMultiValueConverter
#Region "Convert/ConvertBack Methods"
Public Function Convert(ByVal values As Object(), _
ByVal targetType As Type, ByVal parameter As Object, _
ByVal culture As CultureInfo) As Object _
Implements IMultiValueConverter.Convert
Dim extra As Double = 0
If values Is Nothing OrElse values.Length < 2 Then
Throw New ArgumentException("The MidpointValueConverter
class requires 2 double values to be passed to it.
First pass the TotalWidth, then the Width.", "values")
End If
Dim totalWidth As Double = CDbl(values(0))
Dim width As Double = CDbl(values(1))
If parameter IsNot Nothing Then
extra = System.Convert.ToDouble(parameter)
End If
Return DirectCast((((totalWidth - width) / 2) + extra), Object)
End Function
Public Function ConvertBack(ByVal value As Object, _
ByVal targetTypes As Type(), ByVal parameter As Object, _
ByVal culture As CultureInfo) As Object() _
Implements IMultiValueConverter.ConvertBack
Throw New NotImplementedException()
End Function
#End Region
End Class
In the MidPointValueConverter class you grab the two values passed in, which are the total width/height of the Canvas and then the total width/height of the TextBlock control. You can then subtract those two values and divide by 2 to get the location of either the Left or the Top property.
Notice that you can also pass in an “extra” value in the “parameter” parameter. This extra value can be used if you want to move the TextBlock control down or to the right depending on the shape you use. For example, if you are using a Triangle with the point of the triangle at the top, you might want to move the text a little lower into the widest part of the triangle instead of right in the middle of the triangle. Or, if you have a triangle where the point is to the right, then you might want to move the text a little over to the left. You set this “extra” parameter as the ConverterParameter attribute on the <MultiBinding> as shown in the following XAML.
<Canvas Name="cnvMain2"
Width="50"
Height="50">
<Polygon Points="25,0 0,40 50,40"
Fill="LightBlue"
Stroke="Black"
StrokeThickness="2"></Polygon>
<TextBlock Name="tbSize2"
Foreground="Black"
Text="Avatar">
<Canvas.Left>
<MultiBinding Converter="{StaticResource MidValue}"
ConverterParameter="1">
<Binding ElementName="cnvMain2"
Path="ActualWidth" />
<Binding ElementName="tbSize2"
Path="ActualWidth" />
</MultiBinding>
</Canvas.Left>
<Canvas.Top>
<MultiBinding Converter="{StaticResource MidValue}"
ConverterParameter="7">
<Binding ElementName="cnvMain2"
Path="ActualHeight" />
<Binding ElementName="tbSize2"
Path="ActualHeight" />
</MultiBinding>
</Canvas.Top></TextBlock>
</Canvas>
Figure 3 shows the results of the rectangle with text in it, and the result of using a polygon with the ConverterParameter set.
Figure 3: Shapes, Text and Canvas using Multi-Binding
Summary
This article introduced you to using a Canvas, Shape and TextBlock control to create shapes with text centered within the shape. In addition, you learned the basics of creating a Multi-Binding value converter in WPF to help you perform the centering. You will find a lot of uses for value converters when designing your WPF applications. Sometimes you will just need to convert a single value, but sometimes you will find it necessary to take several values and return a single value. You simply need to create classes that implement either an IValueConverter interface or the IMultiValueConverter interface.
In a WPF application I am building right now, I had a need to create different sets of shapes and put some text within those shapes. The various shapes I needed were things like rectangles, circles, ellipses and triangles. WPF can create these shapes; however, shapes in WPF are not containers, so you cannot add any text inside of them. This article will show you how to put text into each of these shapes in a couple of different ways.
Using a Border Control
If you wish to put text into an Ellipse, you can simulate this using a Border control and play with the Width, Padding and CornerRadius properties of this control. Below is some sample code that draws text like that shown in Figure 1.
<Border CornerRadius="50"
Width="60"
Margin="10"
Padding="4"
Background="Aquamarine"
BorderBrush="Black"
BorderThickness="1">
<TextBlock HorizontalAlignment="Center">Test</TextBlock>
</Border>
Figure 1: Using a Border control to simulate an ellipse.
You can set the width and height of the Border control to create a circle as well. Below is some XAML that creates a circle with text in the middle as shown in Figure 2.
<Border CornerRadius="50"
Width="60"
Height="60"
Margin="10"
Padding="0,20,0,0"
Background="Aquamarine"
BorderBrush="Black"
BorderThickness="1">
<TextBlock HorizontalAlignment="Center">Test
</TextBlock>
</Border>
Figure 2: Using a Border control to simulate a circle.
Using a VisualBrush
If you wish to use a Triangle and put some text within that triangle, you will need to use a Polygon control to create that triangle. For example, here is code to create a triangle without any words in it.
<Polygon Points="25,0 5,30 45,30"
Fill="LightBlue"
Stroke="Black"
StrokeThickness="2" />
To add words, like that shown in Figure 3, you need to use this Polygon control as the background of a TextBlock control. The XAML shown below is what is used to create Figure 3.
<TextBlock Text="Test"
Width="50"
Height="50"
Padding="13,28,0,0">
<TextBlock.Background>
<VisualBrush>
<VisualBrush.Visual>
<Polygon Points="25,0 5,30 45,30"
Fill="LightBlue"
Stroke="Black"
StrokeThickness="2" />
</VisualBrush.Visual>
</VisualBrush>
</TextBlock.Background>
</TextBlock>
There are two keys to this XAML. First, you use the VisualBrush object of the Background of the TextBlock object to give you a place to put the Polygon control. Secondly, depending on the Text that you fill into the TextBlock control, and the width and height of the TextBlock control, you will need to play with the Padding property to align the text to the correct location. Take the above XAML and put it in a new window and then adjust the height, width and text values. You will see that you need to adjust the Padding property to make the text fall into the correct location.

Figure 3: Using a Visual Brush.
Here is another example of a Visual Brush, this time using an Ellipse control. The results of this XAML can be seen in Figure 4.
<TextBlock Text="Test"
Height="40"
Width="40"
Padding="8,10,0,0">
<TextBlock.Background>
<VisualBrush>
<VisualBrush.Visual>
<Ellipse Height="20"
Width="20"
Fill="LightBlue" />
</VisualBrush.Visual>
</VisualBrush>
</TextBlock.Background>
</TextBlock>
Notice the Padding is different from the Padding used when using the Polygon control. You will need to make minor adjustments based on the shape that you are using and the height and width of the control, and the text you are putting into the TextBlock.
Figure 4: Using an Ellipse as the background for a TextBlock
Summary
This article presented a couple of different methods of placing text in the middle of shape objects in WPF. You do have to do some tweaking of properties to get the text to appear in the middle of the shape, but for many uses, these techniques work well. In my next blog post, I will show you how to use a Canvas, a Shape, a TextBlock and a multi-binding value converter to center the text automatically.
NOTE: You can download the complete sample code at my website. http://www.pdsa.com/downloads. Choose Tips & Tricks, then "WPF Text and Shapes" from the drop-down.
Good Luck With Your Coding,
Paul Sheriff
** SPECIAL OFFER FOR MY BLOG READERS **
Visit http://www.pdsa.com/Event/Blog for a free eBook on "Fundamentals of N-Tier".
Recently, I have been setting up a lot of WPF styles for an application I am working on. During this project, I needed to set a lot of colors. Instead of hard-coding colors, I use resources. For example, I am using the <DropShadowEffect> on many of my controls. This <DropShadowEffect> element has a “Color” attribute that you can set as shown in the code below:
<Border.Effect>
<DropShadowEffect
BlurRadius="10"
Color="Gray" />
</Border.Effect>
Instead of hard-coding the color “Gray”, I would like to use a resource. I can’t just create a string resource and put that into the Color attribute. You must use a <Color> resource. Thus, I need to create a Color resource that looks like the following:
<Color x:Key="pdsaDropShadowEffectColor"
R="128"
B="128"
G="128" />
Well, I don’t know about you, but I do not remember all of the (R)ed, (G)reen, and (B)lue color numbers off the top of my head. Thus, I needed a little utility that would help me get these numbers for the color I was looking for. In Figure 1 you can see a utility I wrote to help me do this.

Figure 1: Utility to display all the WPF colors and retrieve the RGB values
Loading a List Box with WPF Colors
The first thing this utility needs to do is to load all the WPF colors into a list box. You can get the complete list of Colors using an ObjectDataProvider object, however setting up the ObjectDataProvider can be a little tricky. One thing that helps me immensely – and I hope will work for you -- is to write a little code that will return a collection of items. Once I have that, I usually find it is very easy to convert that code to use an ObjectDataProvider.
To retrieve the WPF Colors is also a little tricky, as the Colors class contains individual static/Shared properties, one property to represent each color. So you need to use reflection to get the collection of properties. Each property of the Colors class is a Color object. So once you have each Color object, you then need all of its properties so you can retrieve the Name property. Once you have the Name property you can bind that property to the list box shown in Figure 1. Below is some sample code you might write to retrieve and print out each individual color name from the Colors class. NOTE: This code is not used in this project, it is just here as an example of how to use reflection to get the list of properties of a Color object.
C#
using System.Reflection;
using System.Diagnostics;
private void GetColorEnumsAsString()
{
PropertyInfo[] clrs = Type.GetType(
"System.Windows.Media.Colors, PresentationCore,
Version=3.0.0.0, Culture=neutral,
PublicKeyToken=31bf3856ad364e35").GetProperties();
foreach (PropertyInfo item in clrs)
{
Debug.WriteLine(item.Name);
}
}
Visual Basic
Imports System.Reflection
Imports System.Diagnostics
Private Sub GetColorEnumsAsString()
Dim clrs As PropertyInfo() = Type.GetType( _
"System.Windows.Media.Colors, PresentationCore,
Version=3.0.0.0, Culture=neutral,
PublicKeyToken=31bf3856ad364e35").GetProperties()
For Each item As PropertyInfo In clrs
Debug.WriteLine(item.Name)
Next
End Sub
In the above code, you first use the GetType method of the Type class. You pass to this method the fully qualified class name including the namespace and the assembly information. For any class that is not in the System assembly, you need to use the full assembly qualification. Once you retrieve the Type, you call the GetProperites method on type to get a collection of PropertyInfo objects. It is in the PropertyInfo object that you can get the Name property. Since the name of the property is the name of the color, you bind the Name property to the list box.
Using the ObjectDataProvider
From the above code you can then figure out how to lay out your ObjectDataProvider, or in this case, two ObjectDataProvider objects. As you can see in the above code, you need to perform two operations to get the final collection. First, you call the GetType method, then you call GetProperties method. This means you need to use two ObjectDataProviders. The first ObjectDataProvider you create looks like the following:
<ObjectDataProvider MethodName="GetType"
ObjectType="{x:Type sys:Type}"
x:Key="odpColors">
<ObjectDataProvider.MethodParameters>
<sys:String>
System.Windows.Media.Colors, PresentationCore,
Version=3.0.0.0, Culture=neutral,
PublicKeyToken=31bf3856ad364e35
</sys:String>
</ObjectDataProvider.MethodParameters>
</ObjectDataProvider>
In the above ObjectDataProvider you are creating an instance of the Type object located in the “sys” namespace. You need to add the “sys” namespace to your Window object. You do this by adding the following XAML within your Window declaration:
<Window x:Class="PDSAConvertColorToRGB.winMain"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:sys="clr-namespace:System;assembly=mscorlib"
...
The ObjectDataProvider has the ability to pass a parameter to the object you instantiate through the <ObjectDataProvider.MethodParameters>. The parameter in the MethodParameters is the exact string used in the code shown earlier. The next ObjectDataProvider uses the first ObjectDataProvider as its source of data and then calls the GetProperties method on this souce.
<ObjectDataProvider ObjectInstance="{StaticResource odpColors}"
MethodName="GetProperties"
x:Key="odpColorNames">
</ObjectDataProvider>
For this second ObjectDataProvider the data is the instance of the data of the first ObjectDataProvider. You call the GetProperties method on the data type in the first ObjectDataProvider to give you Color object collection to which you can bind to the ListBox control on the Window.
Defining the ListBox
Once you have the collection of Color objects you now bind them to the list box control. For this list box, you want to not only have the name of the color displayed, but also a display of the actual color. To accomplish this you use a DataTemplate and layout the display of each list item. Each list item will use a label for the name of the color, and will set the Fill attribute of a Rectangle control to display the actual color. A thin black border will be used around the Rectangle control to clearly define the color swatch.
<ListBox Name="lstColors"
Height="200"
TextSearch.TextPath="Name"
IsTextSearchEnabled="True"
ItemsSource="{Binding
Source={StaticResource odpColorNames}}"
SelectedValuePath="Name">
<ListBox.ItemTemplate>
<DataTemplate>
<StackPanel Orientation="Horizontal">
<Label Width="140"
Margin="4"
Content="{Binding Path=Name}" />
<Border BorderBrush="Black"
BorderThickness="1"
Margin="4">
<Rectangle Width="140"
Fill="{Binding Path=Name}" />
</Border>
</StackPanel>
</DataTemplate>
</ListBox.ItemTemplate>
</ListBox>
The final piece of the list box control is the setting of the SelectedValuePath. Setting this value to Name will allow you to retrieve the name of the Color object and use that object to extract the Red, Green and Blue color values.
Getting the Color Object
After you select a specific color from the list box, you click on the Get Color button on the window. This button will fire its Click event procedure shown in the code below.
C#
private void btnGetColor_Click(object sender, RoutedEventArgs e)
{
Color clr = new Color();
clr = (Color)ColorConverter.ConvertFromString(
lstColors.SelectedValue.ToString());
lblRed.Content = clr.R.ToString();
lblGreen.Content = clr.G.ToString();
lblBlue.Content = clr.B.ToString();
}
Visual Basic
Private Sub btnGetColor_Click(ByVal sender As System.Object, _
ByVal e As System.Windows.RoutedEventArgs)
Dim clr As New Color()
clr = DirectCast(ColorConverter.ConvertFromString( _
lstColors.SelectedValue.ToString()), Color)
lblRed.Content = clr.R.ToString()
lblGreen.Content = clr.G.ToString()
lblBlue.Content = clr.B.ToString()
End Sub
You first retrieve the name of the color from the SelectedValue property of the list box. Then you use the ColorConverter class to convert the name of the color to an actual Color object. Once you have the Color object, you can now extract the R, G and B properties of the color and display those values in each of the appropriate labels.
Summary
With just a tiny little bit of code you are able to extract the R, G and B properties from a Color object. These values can then be used to create <Color> resources in WPF or Silverlight. This handy utility is also a good tutorial on data binding and how to work with reflection. I hope this sample helped you.
NOTE: You can download the complete sample code at my website. http://www.pdsa.com/downloads. Choose Tips & Tricks, then "WPF: Color To RGB" from the drop-down.
Good Luck With Your Coding,
Paul Sheriff
** SPECIAL OFFER FOR MY BLOG READERS **
Visit http://www.pdsa.com/Event/Blog for a free eBook on "Fundamentals of N-Tier".
One of the really cool features of WPF is the ability to style controls. Styles in WPF can be grouped together into Resource Dictionaries. These resource dictionaries can then be loaded dynamically at runtime with just a small amount of Visual Basic or C# code. In Figure 1 you see an example WPF form that allows you to type in a XAML file name that contains a resource dictionary. The styles within this resource dictionary are applied to a Grid control. In this case, it is just a simple gradient fill, but the same concept will apply even if you had styles for all controls in your application.
Figure 1: Loading resources on the fly allows you to change styles at runtime
The Resource Dictionaries
A resource dictionary is nothing more than a collection of styles grouped together under a <ResourceDictionary> xaml tag. Each style can be keyed, or have just a TargetType attribute. The samples in this article are very simple and just have one Style that applies to a Grid control. The style will set the Background property of a Grid to a LinearGradientBrush of a certain set of colors. Below is the Green.xaml file.
<ResourceDictionary
xmlns=http://schemas.microsoft.com/winfx/2006/xaml/presentation
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml">
<Style TargetType="Grid"
x:Key="DynamicGridBrush">
<Setter Property="Background">
<Setter.Value>
<LinearGradientBrush StartPoint="0,0"
EndPoint="0,1">
<GradientStop Offset="0"
Color="LightBlue" />
<GradientStop Offset="0.65"
Color="LightGreen" />
<GradientStop Offset="1"
Color="White" />
</LinearGradientBrush>
</Setter.Value>
</Setter>
</Style>
</ResourceDictionary>
Next, is the Blue.xaml resource dictionary.
<ResourceDictionary
xmlns=http://schemas.microsoft.com/winfx/2006/xaml/presentation
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml">
<Style TargetType="Grid"
x:Key="DynamicGridBrush">
<Setter Property="Background">
<Setter.Value>
<LinearGradientBrush StartPoint="0,0"
EndPoint="0,1">
<GradientStop Offset="0"
Color="Blue" />
<GradientStop Offset="0.65"
Color="LightBlue" />
<GradientStop Offset="1"
Color="AliceBlue" />
</LinearGradientBrush>
</Setter.Value>
</Setter>
</Style>
</ResourceDictionary>
Now that you have the resource dictionaries defined you will now want to switch between them dynamically at runtime.
Setting the Style
In the form shown in Figure 1 you see a grid with a linear gradient. This is accomplished using the following code:
<Grid Style="{DynamicResource DynamicGridBrush}"
Height="180"
Width="250" />
Notice the use of the {DynamicResource DynamicGridBrush}. This code allows your XAML code to compile even if it can’t find the “DynamicGridBrush” at compile-time. The DynamicResource keyword says to look for this resource, but if you can’t find that resource, then just do not set the Style at this time. If after loading a new resource dictionary the style becomes available, then go ahead and apply the style.
Loading a Resource
To load a XAML file from disk, you will first need to open that file as a file stream. Next you can use the XamlReader class from the System.Windows.Markup namespace to load that file stream and cast it into a ResourceDictionary. You can then clear any old dictionaries that were previously loaded. Next you add to the MergedDictionaries collection of the current Window’s Resources property the dictionary you just loaded from disk.
C#
private void DynamicLoadStyles()
{
string fileName;
fileName = Environment.CurrentDirectory() +
@"\Dictionaries\" + txtXamlName.Text;
if (File.Exists(fileName))
{
using (FileStream fs = new FileStream(fileName, FileMode.Open))
{
// Read in ResourceDictionary File
ResourceDictionary dic =
(ResourceDictionary)XamlReader.Load(fs);
// Clear any previous dictionaries loaded
Resources.MergedDictionaries.Clear();
// Add in newly loaded Resource Dictionary
Resources.MergedDictionaries.Add(dic);
}
}
else
MessageBox.Show("File: " + txtXamlName.Text +
" does not exist. Please re-enter the name.");
}
VB.NET
Private Sub DynamicLoadStyles()
Dim fileName As String
Dim dic As ResourceDictionary = Nothing
fileName = Environment.CurrentDirectory & _
"\Dictionaries\" & txtXamlName.Text
If File.Exists(fileName) Then
Using fs As FileStream = New FileStream(fileName, _
FileMode.Open)
' Read in ResourceDictionary File
dic = CType(XamlReader.Load(fs), ResourceDictionary)
' Clear any previous dictionaries loaded
Resources.MergedDictionaries.Clear()
' Add in newly loaded Resource Dictionary
Resources.MergedDictionaries.Add(dic)
End Using
Else
MessageBox.Show("File: " + fileName + _
" does not exist. Please re-enter.")
End If
End Sub
To ensure that you can access the Green.xaml and the Blue.xaml files you need to add each of them to your Visual Studio solution in a folder called \Dictionaries. Next you need to click on each of these files in turn and bring up the Properties Window. Change the Build Action to “Content” and the Copy to Output Directory to “Copy Always”. This ensures that the Environment.CurrentDirectory plus the directory plus the file name will find the appropriate file at runtime.
Summary
Having the ability to load resource dictionaries at runtime can aid you a lot in changing the look and feel of a WPF application. You can have a set of styles that a user is allowed to choose from. You could then store their choice in a user table, and load that value when the application starts up. This allows you to customize each user’s experience with your application. You can control color, font size and many other attributes about a user’s experience with your user interface.
NOTE: You can download the complete sample code at my website. http://www.pdsa.com/downloads. Choose Tips & Tricks, then "WPF: Dynamically Load Resources" from the drop-down.
Good Luck With Your Coding,
Paul Sheriff
** SPECIAL OFFER FOR MY BLOG READERS **
Visit http://www.pdsa.com/Event/Blog for a free eBook on "Fundamentals of N-Tier".
Hi All,
I will be giving 4 hours of real-world training on WPF this Wednesday (Nov. 18th, 2009). If you are new to WPF and wanting to learn how to use WPF to create business applications, this is a great place to start. The cost for this seminar is only $99. You can sign up at http://www.pdsa.com/learning.
I hope to see you there!
Paul D. Sheriff
If anyone is at PDC this week, I will be moderating a session on Exception Management. If you would like to discuss this topic with your other peers at PDC, please stop by!
Hope to see you there!
Paul
WPF has the flexibility to modify the look of your controls dynamically at runtime with just a few lines of code. Take a look at Figures 1 and 2 and you will see two different views of the same list box and data. To accomplish this, you simply need to setup two different resources of XAML code that you can switch between at runtime.
Figure 1: More detail

Figure 2: Less detail
The Basic Form and the Data
This XAML form uses an XML file to fill in the ListBox control with the product data. There is a folder called \Images where the pictures for the various products are located. Below is a fragment of the XML file that contains the product data.
<Products>
<Product>
<ProductId>1</ProductId>
<ProductName>PDSA .NET Productivity Framework</ProductName>
<Price>5000</Price>
<Logo>/Images/Framework.gif</Logo>
</Product>
...
...
</Products>
An XmlDataProvider control is used to load this file and supply the data for the list box. The XAML code shown below is the setup of this XmlDataProvider. This XmlDataProvider is located within the Window.Resources section of this WPF Window.
<XmlDataProvider x:Key="xProducts"
Source="/Product.xml"
XPath="Products/Product" />
As you can see in the above code the Product.xml file is located in the root of the project. You use the XPath attribute to read to the node level where the actual data is within the XML file. Then you will be able to specify the element name of where the data is for displaying in the list box.
Create the XAML Templates
The next items in the Window.Resources section of this WPF Window are the <DataTemplates>. There are two data templates created as resources in this window. One has a key of “tmplMore” and one has a key of “tmplLess”. Below is the XAML code that is used to create the list box that looks like Figure 1. You can see the use of a Horizontal StackPanel control, and an Image control as the first control within that StackPanel.
<DataTemplate x:Key="tmplMore">
<StackPanel Orientation="Horizontal">
<Image Margin="8"
Source="{Binding XPath=Logo}"
Width="100"></Image>
<Label Width="250"
Content="{Binding XPath=ProductName}"></Label>
<Label Width="100"
Content="{Binding XPath=Price}"></Label>
</StackPanel>
</DataTemplate>
Notice the data binding of the Source property of the image and the Content properties of the two labels. The Binding uses XPath attribute to signify the name of the element within the XML file. Remember that the XmlDataProvider has the first part of the XPath query, while each Binding is the element where the data is located that will be displayed in the list box.
The next data template created within the Window.Resources section has the key of “tmplLess” and looks like the XAML below. You can see that the Image control is missing from this template.
<DataTemplate x:Key="tmplLess">
<StackPanel Orientation="Horizontal">
<Label Width="250"
Content="{Binding XPath=ProductName}"></Label>
<Label Width="100"
Content="{Binding XPath=Price}"></Label>
</StackPanel>
</DataTemplate>
In the WPF Window is the definition of the list box control shown in the XAML listing below. Notice that the ItemsSource attribute is set to bind to the xProducts XmlDataProvider control. Also notice that the ItemTemplate is bound to the “tmplMore” data template resource. This is the default data template that is used when the window is first displayed.
<ListBox Margin="10,10,0,0"
Height="300"
Name="lstData"
ItemsSource="{Binding Source={StaticResource xProducts}}"
IsSynchronizedWithCurrentItem="True"
ItemTemplate="{StaticResource tmplMore}">
</ListBox>
Switch Between the XAML Templates
You will write code in each button’s click event procedures, shown below, to switch between the two XAML templates. In each event procedure you create a variable to refer to a DataTemplate object. You then use the FindResource method of the current window to find the resource named either “tmplMore” or “tmplLess”. Once you have the data template object you can assign that to the ItemTemplate property of the list box control.
One thing to note is that you should include error handling within this code because if the FindResource method does not find the resource, then it will throw an exception. I purposely left out the code for brevity in this example.
Visual Basic
Private Sub btnMore_Click(ByVal sender As System.Object, _
ByVal e As System.Windows.RoutedEventArgs) Handles btnMore.Click
Dim tmpl As DataTemplate
tmpl = DirectCast(Me.FindResource("tmplMore"), DataTemplate)
lstData.ItemTemplate = tmpl
End Sub
Private Sub btnLess_Click(ByVal sender As System.Object, _
ByVal e As System.Windows.RoutedEventArgs) Handles btnLess.Click
Dim tmpl As DataTemplate
tmpl = DirectCast(Me.FindResource("tmplLess"), DataTemplate)
lstData.ItemTemplate = tmpl
End Sub
C#
private void btnMore_Click(object sender, RoutedEventArgs e)
{
DataTemplate tmpl;
tmpl = (DataTemplate)this.FindResource("tmplMore");
lstData.ItemTemplate = tmpl;
}
private void btnLess_Click(object sender, RoutedEventArgs e)
{
DataTemplate tmpl;
tmpl = (DataTemplate)this.FindResource("tmplLess");
lstData.ItemTemplate = tmpl;
}
Summary
In this article you learned to change templates on a list box control dynamically at runtime using the FindResource method. You simply need to create a couple of XAML templates that you will use to switch between the different views. You create these XAML templates in the Window.Resources section of the window. You give each template a unique name, and then write a little code to find each of the resources at runtime. Once you have located the appropriate resource, you assign it to the ItemTemplate property of the list box and WPF will change the look of the control instantly.
NOTE: You can download the complete sample code at my website. http://www.pdsa.com/downloads. Choose Tips & Tricks, then "WPF Change Templates" from the drop-down.
Good Luck With Your Coding,
Paul Sheriff
** SPECIAL OFFER FOR MY BLOG READERS **
Visit http://www.pdsa.com/Event/Blog for a free eBook on "Fundamentals of N-Tier".
Unlike Windows Forms, there is no Visual Inheritance in WPF. Luckily you don’t need visual inheritance as you can use User Controls to get a re-usable UI. There are times, however, when you want a base Window class so you can have common functionality in all your WPF windows. To accomplish this you can create a base class from which all your WPF windows can inherit. To use the base class you will need to make one simple change in both the XAML and in your code-behind class.
<Window> Element and Window Class
When you add a new Window to a WPF application it builds a .XAML file and a code-behind file. The XAML file has a <Window> element and the code-behind file has a partial class that inherits from “Window” or “System.Windows.Window” to be more specific. Notice the x:Class=”<Namespace>.<ClassName>” syntax in the XAML (See Figure 1). This x:Class name attribute must have the same name as the partial class in the code-behind. At compile time, the .XAML file is converted into a partial class that has the same name as the name of the class in the code-behind and inherits from the name of the top level element in the XAML; in this case “Window”.

Figure 1: The Window class and the inherited Window must match.
As long as these two items match the two elements in the partial class in the code-behind the compiler will be happy. If either of these two elements does not match, you will receive a compiler error.
Inherit from the Window Class
Now that you understand the basics of how the XAML and the code-behind are put together, you can now create a base Window class and modify the XAML and code-behind to use this new class.
If you wish to follow along with this article, create a new WPF application in Visual Studio. Add a new class to your project named WindowBase. Modify this newly added class to inherit from the Window class. Add the following Imports/using statements at the top of the WindowBase class.
C#
using System.Windows;
Visual Basic
Imports System.Windows
The WindowBase class needs to inherit from the Window class by changing the code to look like the following:
C#
using System;
using System.Windows;
namespace WpfApplication1
{
public class WindowBase : Window
{
}
}
Visual Basic
Imports System.Windows
Public Class WindowBase
Inherits Window
End Class
Modify the code-behind of the Window1.xaml file to inherit from the WindowBase class you just created. Your Window1 code-behind should now look like the following:
C#
public partial class Window1 : WindowBase
{
public Window1()
{
InitializeComponent();
}
}
Visual Basic
Class Window1
Inherits WindowBase
End Class
If you were to compile the WPF application right now, you will receive the error message “Base class 'System.Windows.Window' specified for class 'Window1' cannot be different from the base class 'WindowBase' of one of its other partial types.” The reason is because while you changed the code behind to inherit from the WindowBase class, you need to change the XAML markup to reflect this same change.
The change you need to make is you need to modify the <Window> element to be <WindowBase>. However, <WindowBase> is not a part of any of the imported xml namespaces that are a normal part of the XAML markup. Thus, you need to add a namespace reference to the assembly that contains the WindowBase class. If you created a default WPF application project, the namespace you will add to the XAML is the following:
xmlns:src="clr-namespace:WpfApplication1"
Once you have added this namespace with the prefix of “src” you can now change the <Window> element to <src:WindowBase>. Be sure you modify the closing </Window> element to </src:WindowBase>. The complete source code for the XAML is shown below.
C#
<src:WindowBase
x:Class="WpfApplication1.Window1"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:src="clr-namespace:WpfApplication1"
Title="Window1" Height="300" Width="300">
<Grid></Grid>
</src:WindowBase>
Visual Basic
<src:WindowBase
x:Class="Window1"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:src="clr-namespace:WpfApplication1"
Title="Window1" Height="300" Width="300">
<Grid></Grid>
</src:WindowBase>
At this point you should be able to compile the application and everything should compile correctly.
Adding Functionality
Now that you have a base Window class you can add code to that class that can be used in all of your WPF Windows. Once piece of functionality you might need is to check if your Window is in design mode or runtime. Add the following property to your WindowBase class.
C#
public bool IsInDesignMode
{
get
{
return System.ComponentModel.
DesignerProperties.GetIsInDesignMode(this);
}
}
Visual Basic
Public ReadOnly Property IsInDesignMode() As Boolean
Get
Return System.ComponentModel. _
DesignerProperties.GetIsInDesignMode(Me)
End Get
End Property
From within your Window that inherits from the WindowBase class you can test to see if you are in design mode or in runtime mode.
C#
if(IsInDesignMode)
// Do Something
Visual Basic
If IsInDesignMode Then
' Do Something
End If
Another piece of code that might come in handy in your WPF windows is the ability to read a resource dictionary XAML file and load it into the Resources of the Window. Below is the code you would add to the WindowBase class to do this.
C#
using System.IO;
using System.Windows.Markup;
public void OpenResourceDictionary(string fileName)
{
ResourceDictionary dic = null;
if (File.Exists(fileName))
{
using (FileStream fs = new FileStream(fileName, FileMode.Open))
dic = (ResourceDictionary)XamlReader.Load(fs);
this.Resources.MergedDictionaries.Add(dic);
}
else
throw new FileNotFoundException(
"Can't open resource file: " + fileName +
" in the method OpenResourceDictionary().");
}
Visual Basic
Imports System.IO
Imports System.Windows.Markup
Public Sub OpenResourceDictionary(ByVal fileName As String)
Dim dic As ResourceDictionary = Nothing
If File.Exists(fileName) Then
Using fs As New FileStream(fileName, FileMode.Open)
dic = DirectCast(XamlReader.Load(fs), ResourceDictionary)
End Using
Me.Resources.MergedDictionaries.Add(dic)
Else
Throw New FileNotFoundException( _
"Can't open resource file: " & fileName & _
" in the method OpenResourceDictionary().")
End If
End Sub
When you wish to load a new resource dictionary file at runtime into your Window you may do so with some very simple code from within your Window.
C#
OpenResourceDictionary("D:\Samples\Green.xaml");
Visual Basic
OpenResourceDictionary("D:\Samples\Green.xaml")
Summary
So, that is all there is to creating your own base Window class from which all your Window objects can inherit. There is a lot of functionality that you will want to make available to your Window classes. Creating a base Window class is a great way to expose this functionality. It just takes a little bit of tweaking to your XAML and your code-behind to get all this great functionality.
NOTE: You can download the complete sample code at my website. http://www.pdsa.com/downloads. Choose Tips & Tricks, then "WPF Window Inheritance" from the drop-down.
Good Luck With Your Coding,
Paul Sheriff
** SPECIAL OFFER FOR MY BLOG READERS **
Visit http://www.pdsa.com/Event/Blog for a free eBook on "Fundamentals of N-Tier".
More Posts
Next page »