jump to navigation

Using Type Converters in WPF July 31, 2011

Posted by fofo in C#, c# 3.0, c# 4.0, general .net, Visual Studio 2008, Visual Studio 2010, VS 2010, WPF, XAML.
Tags:
trackback

In this post I would like to talk/show you how to implement type conversions in WPF.

We must talk a little bit for Binding in WPF before we move on to explain why we use type converters and show a hands on example.

So what is Binding in WPF? In WPF we can bind any property of any object to any other property of some other object.

Binding is typically done in XAML by using the Binding markup extensions.For example

<TextBox Text=”{Binding Path=Property}” />

The syntax above implies that we do not set the value of the Target to some literal value.

When we use binding in XAML , what really happens is that in runtime we create an instance of the Binding class, setting various properties that affect its behaviour.

We can create bindings in code as well. Basically in WPF it is entirely up to the developer if he will write any XAML code to implement the application.

I strongly recommend to use the XAML approach.

In binding we have a Target object/element. In order for binding to be possible, that object/element must inherit from (be an object of type) FrameworkElement.

In the previous small example, TextBox is a Control and inherits from FrameworkElement class. All controls inherit from that class. So all the WPF controls and their properties/attributes can be part of a Binding situation.

Speaking of properties/attibutes the Target property must be a DepenencyProperty. So the “Text” property in the previous example is a Dependency property.

Obviously we need to have some sort of source to bind to.Any .Net object can be a binding source.We can display customers from a customer object in a ListBox control.

We can bind to datasets and entity classes. We can bind to properties of other elements. For example we can bind the value of a Slider control to a TextBlock.

So we can bind from various sources. Basically any CLR object can play the role of the Binding source.

We can specify the mode of how data flows between the data and the source. So we have

  • TwoWay – Data flows both directions
  • OneWay – Data flows only from the source to the target
  • OneTime – Data flows only from the source to the target but we bind only once to the source. It is a useful only if we do not expect the source to change.
  • OneWayToSource – Data flows from the target to the source, for example, we have a textbox that we tell it not to bother read the initial value from the source but update the source with any value the user types in

In order to have a better idea how binding works have a look at the picture below

So where value converters figure in the above scenario? In many cases the binding source is of a type that needs to be converted so that the target property can bind to.

Value converters are instances of classes that implement the IValueConverter interface.

I will create a hands on example to demonstrate how to use type converters in WPF.

1) Launch Visual Studio 2010/2008. From the available templates, choose a WPF application template.Choose an appropriate name for your application. I have named it WpfApplicationConverters. I will use C# as the development language.

2) We will create a simple WPF application , with a button, 2 comboboxes and a border. The first combobox will load with various font families.Every time the user will select a different font from the combobox the FontFamily attribute of the Button element will reflect those changes.

3) The second combobox will load with integer values ( 1-10). Every time the user selects a different value from this combobox then the BorderThickness property of the Border element will change to reflect this change.

In both cases we need to need some sort of value conversions. The values in the FontFamily Combobox are of type String and we need to convert it to FontFamily type.

The values of the second combobox has integer values.These values need to be mapped to another type, the BorderThickness property.The BorderThickness property has four values.

We need to have some sort of classes where we make the conversion.

4) We need to write the UI first. The XAML for the UI follows

<Window x:Class="WpfApplicationConverters.MainWindow"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
Title="MainWindow" Height="350" Width="525">

<StackPanel>

<Border BorderBrush="DarkCyan" >

<StackPanel>

<Grid Height="210">

<Button FontSize="16"  Content="I am a button"  Height="34"  Name="button1" Width="164"   Margin="166,41,161,135" />

<ComboBox Height="32" Name="BorderThicknessComboBox" Width="120" Margin="82,128,289,50"   />

<ComboBox Name="FontFamilyComboBox" Width="136" Height="34"  Margin="243,128,112,48"></ComboBox>

</Grid>

</StackPanel>

</Border>

</StackPanel>

</Window>

5) Run your application and make sure it works.

Now I need to populate the comboxoxes with the initial values. I will use the Loaded event of each control.

I will write the code in the MainWindow.xaml.cs file.

using System.Windows;
using System.Linq;
using System.Collections.Generic;

namespace WpfApplicationConverters
{
/// <summary>
/// Interaction logic for MainWindow.xaml
/// </summary>
public partial class MainWindow : Window
{
public MainWindow()
{

InitializeComponent();
}

private void ThicknessComboBoxSetUp()
{
BorderThicknessComboBox.ItemsSource = Enumerable.Range(1, 10);
BorderThicknessComboBox.SelectedIndex = 0;
}

private void FillComboBoxWithFontFamilies()
{

FontFamilyComboBox.ItemsSource = new List<string>() { "Arial", "Arial Black", "Comic Sans MS", "Courier New", "Georgia",
            "Lucida Sans Unicode", "Times New Roman", "Trebuchet MS", "Verdana" };
FontFamilyComboBox.SelectedIndex = 0;
}

private void FontFamilyComboBox_Loaded(object sender, RoutedEventArgs e)
{
FillComboBoxWithFontFamilies();
}

private void BorderThicknessComboBox_Loaded(object sender, RoutedEventArgs e)
{
ThicknessComboBoxSetUp();
}

6) The code above is very easy to follow and understand.I create two methods ThicknessComboBoxSetup() and FillComboBoxWithFontFamilies() and then use these methods in the BorderThicknessComboBox_Loaded and FontFamilyComboBox_Loaded event handling routines.

Obviously you need to change the XAML code as well.


<ComboBox Height="32" Name="BorderThicknessComboBox" Width="120" Margin="82,128,289,50" Loaded="BorderThicknessComboBox_Loaded"/>

<ComboBox Name="FontFamilyComboBox" Width="136" Height="34"  Margin="243,128,112,48" Loaded="FontFamilyComboBox_Loaded" />

7) Run your application and make sure everything works as expected. Now we will implement the type value converters.

Add a new item to the project, a class file. Name it FontFamilyConversions.cs. The code for the class follows

using System.Windows.Media;
using System.Windows.Data;

namespace WpfApplicationConverters
{
class FontFamilyConversions: IValueConverter
{

public object Convert(object value, System.Type targetType, object parameter, System.Globalization.CultureInfo culture)
{
FontFamily fontfamily = new FontFamily("Verdana");
if (value != null)
{
fontfamily = new FontFamily(value.ToString());
}
return fontfamily;
}

public object ConvertBack(object value, System.Type targetType, object parameter, System.Globalization.CultureInfo culture)
{
return null;
}
}
}

8) The code above is easy to understand. I implement the IValueConverter interface and the to methods, Convert and ConvertBack methods.

I actually implement only the Convert method.I convert the string value to a new value of type FontFamily.

9) Add a new class to the project so you can perform the second conversion.Name it IntergerToThicknessConversions.cs

The conversion in this case will be from a type integer to a type Thickness.The code for the class follows


using System;
using System.Windows.Data;
using System.Windows;

namespace WpfApplicationConverters
{
class IntergerToThicknessConversions:IValueConverter
{
public object Convert(object value, Type targetType, object parameter, System.Globalization.CultureInfo culture)
{
Thickness thicknessValue = new Thickness(0);

if (value != null)
{
thicknessValue =
new Thickness(System.Convert.ToInt32(value));
}
return thicknessValue;

}

public object ConvertBack(object value, Type targetType, object parameter, System.Globalization.CultureInfo culture)
{
throw new NotImplementedException();
}
}
}

10) Now we need to hook these classes with the XAML.The first thing I do is to add the namespace of all the classes in our project.

 xmlns:local="clr-namespace:WpfApplicationConverters"

Then I need to define the classes that implement the type conversions. I do that inside a Window.Resources element.

<Window.Resources>
    <local:FontFamilyConversions x:Key="FontFamilyConversions" />
    <local:IntergerToThicknessConversions x:Key="IntergerToThicknessConversions" />
</Window.Resources>

The last thing is to bind the target properties to the Comboboxes selected values and the Conversion classes.  I use markup extensions in XAML. I bind to the appropriate combobox for each case, then set the Path property to the SelectedValue. For the conversions I use the Converter attribute to bind to the appropriate conversion classes.

<Border BorderBrush="DarkCyan"  BorderThickness="{Binding ElementName=BorderThicknessComboBox, 
Path=SelectedValue, Converter={StaticResource IntergerToThicknessConversions}}">

<Button FontSize="16"  Content="I am a button"  Height="34"  Name="button1" Width="164" 
FontFamily="{Binding SelectedValue,ElementName=FontFamilyComboBox, Mode=OneWay,  
 Converter={StaticResource FontFamilyConversions}}" Margin="166,41,161,135" />

The whole code for the UI is this


<Window x:Class="WpfApplicationConverters.MainWindow"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
Title="MainWindow" Height="350" Width="525"
xmlns:local="clr-namespace:WpfApplicationConverters"
>
<Window.Resources>
<local:FontFamilyConversions x:Key="FontFamilyConversions" />
<local:IntergerToThicknessConversions x:Key="IntergerToThicknessConversions" />
</Window.Resources>
<StackPanel>

<Border BorderBrush="DarkCyan"  BorderThickness="{Binding ElementName=BorderThicknessComboBox, Path=SelectedValue,
Converter={StaticResource IntergerToThicknessConversions}}">

<StackPanel>

<Grid Height="210">

<Button FontSize="16"  Content="I am a button"  Height="34"  Name="button1" Width="164"  FontFamily="{Binding SelectedValue, ElementName=FontFamilyComboBox, Mode=OneWay, Converter={StaticResource FontFamilyConversions}}" Margin="166,41,161,135" />

<ComboBox Height="32" Name="BorderThicknessComboBox" Width="120" Margin="82,128,289,50"  Loaded="BorderThicknessComboBox_Loaded"  />

<ComboBox Name="FontFamilyComboBox" Width="136" Height="34"  Loaded="FontFamilyComboBox_Loaded" Margin="243,128,112,48"></ComboBox>
</Grid>
</StackPanel>
</Border>
</StackPanel>
</Window></pre>

Run your application and change the Font Family for the button and the Thickness of the border. Make sure everything works as expected.

Email me if you need the source code.
Hope it helps !!!

Comments»

1. Kashif Mujeeb - August 1, 2011

Thanks for Sharing ….

2. Subha - March 14, 2013

Thanks for sharing i tryied this but it is not working properly.can you send the code

3. Chandra Dev - May 26, 2013

It really excellent post. You have written in very nice ways.


Leave a Reply

Fill in your details below or click an icon to log in:

WordPress.com Logo

You are commenting using your WordPress.com account. Log Out / Change )

Twitter picture

You are commenting using your Twitter account. Log Out / Change )

Facebook photo

You are commenting using your Facebook account. Log Out / Change )

Google+ photo

You are commenting using your Google+ account. Log Out / Change )

Connecting to %s

%d bloggers like this: