Introduction
In WPF, custom value converters can be used to convert data from one type to another. A custom converter can be used to implement custom logic to convert one value to another. To demonstrate this article, I have developed an application in Visual C# 2010 Express Edition, that takes a decimal value as input and converts it into binary, octal, and hexadecimal values.
Background
To create a custom converter, we need to implement the IValueConverter
interface in our user-defined converter class. The IValueConverter
interface has two methods which we must implement in our class. These methods are as follows:
Convert
: This method converts a source value to target. This method's signature is as follows:
public object Convert(object value, Type targetType, object parameter, System.Globalization.CultureInfo culture)
In this method we code the logic for our custom conversion.
ConvertBack
: This method converts a value back from target to source. This method's signature is same as the Convert
method. We can avoid writing custom code in this method if we do not want to convert a value back to source.
Using the Code
The following XAML code is used to define the user interface of our application:
<Window x:Class="NumberSystemConversion.MainWindow"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:local="clr-namespace:NumberSystemConversion"
Background="BlanchedAlmond"
Title="Number System Converter" Height="350" Width="600">
<Window.Resources>
<local:NumberSystemConverter x:Key="myConverter"/>
</Window.Resources>
<Canvas>
<Label Canvas.Left="100" Canvas.Top="10" FontFamily="Comic Sans MS"
FontSize="32" Foreground="Fuchsia">Number System Converter</Label>
<Label Canvas.Left="40" Canvas.Top="100" FontFamily="Aharoni" FontSize="24"
Foreground="BlueViolet">Enter a Decimal Number: </Label>
<TextBox Name="txtDecimal" Canvas.Left="330" Canvas.Top="100" Width="225"
FontFamily="Aharoni" FontSize="24"
Foreground="BlueViolet" Background="LightPink"/>
<Label Canvas.Left="220" Canvas.Top="150" FontFamily="Lucida Console"
FontSize="24" Foreground="Red">Binary:</Label>
<TextBlock Name="txtBinary" Canvas.Left="330" Canvas.Top="150" Width="225"
FontFamily="Lucida Console" FontSize="24" Foreground="Red" Background="LightPink"
Text="{Binding ElementName=txtDecimal,Path=Text,Converter={StaticResource myConverter},ConverterParameter=2}"/>
<Label Canvas.Left="233" Canvas.Top="200" FontFamily="Lucida Console"
FontSize="24" Foreground="Green">Octal:</Label>
<TextBlock Name="txtOctal" Canvas.Left="330" Canvas.Top="200" Width="225"
FontFamily="Lucida Console" FontSize="24" Foreground="Green" Background="LightPink"
Text="{Binding ElementName=txtDecimal,Path=Text,Converter={StaticResource myConverter},ConverterParameter=8}"/>
<Label Canvas.Left="147" Canvas.Top="250" FontFamily="Lucida Console"
FontSize="24" Foreground="Blue">Hexadecimal:</Label>
<TextBlock Name="txtHexadecimal" Canvas.Left="330" Canvas.Top="250" Width="225"
FontFamily="Lucida Console" FontSize="24" Foreground="Blue" Background="LightPink"
Text="{Binding ElementName=txtDecimal,Path=Text,Converter={StaticResource myConverter},ConverterParameter=16}"/>
</Canvas>
</Window>
In the above code, I have created a window resource called myConverter
which points to our custom converter class called NumberSystemConverter
. A TextBox
called txtDecimal
is used to accept a number to be converted. Three TextBlock
s: txtBinary
, txtOctal
, and txtHexadecimal
are used to display the converted results. The three TextBlock
s are bound to the txtDecimal
TextBox
using element binding. The converter NumberSystemConverter
is used to convert the decimal number to binary, octal, and hexadecimal using the Converter
property. The ConverterParameter
property is used to specify the target type as 2, 8, and 16 for converting to binary, octal, and hexadecimal values, respectively.
Following is the code of our Number System Converter:
public class NumberSystemConverter : IValueConverter
{
Stack<object> stack = new Stack<object>();
public object Convert(object value, Type targetType, object parameter,
System.Globalization.CultureInfo culture)
{
object[] digits = { 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, "A", "B", "C", "D", "E", "F" };
try
{
int number = System.Convert.ToInt32(value.ToString());
if (number == 0)
{
return 0;
}
int divisor = System.Convert.ToInt32(parameter.ToString());
while (number > 0)
{
int remainder = number % divisor;
stack.Push(digits[remainder]);
number /= divisor;
}
StringBuilder builder = new StringBuilder();
while (stack.Count > 0)
{
builder.Append(stack.Pop().ToString());
}
return builder.ToString();
}
catch (Exception)
{
return null;
}
}
public object ConvertBack(object value, Type targetType, object parameter,
System.Globalization.CultureInfo culture)
{
throw new NotImplementedException();
}
}
In the above code, the first parameter of the Convert
method represents the number to be converted (number) and the third parameter represents the target number system (divisor). The number is divided by the divisor and the remainder is pushed into a stack. At the end, the numbers are popped out of the stack and appended to a StringBuilder
object. The StringBuilder
is converted to String
and returned as the result to be displayed on the target TextBlock
.
The ConvertBack
method is not required to be implemented.
Points of Interest
Though there are many more uses of converters and a variety of ways of using converters, I hope that the above discussion would help in understanding the working of converters in WPF.