Introduction
Software is required to represent display components with different values than one used for storing. WPF provides the feature of Converter
(IValueConverter
/IMultiValueConverter
) to do such conversion with ease. We will see how to use converter
s and the optimum way of accessing the converter
s using MarkupExtension
.
Background
Markup Extension is a built in feature provided by WPF framework for extending XAML. Markup extension is defined within curly braces ({}
).
Few Inbuilt extensions provided by WPF framework are:
BindingExtension
StaticResourceExtension
DynamicResourceExtension
RelativeSourceExtension
StaticExtension
TypeExtension
Just like Dependency property or attributes, we don't need to write the word ‘extension’ when accessing it in XAML.
Using the Code
The article is primarily divided into two parts as follows:
- Use of Converter in WPF
- Use of
MarkupExtension
to optimize the construction of Converter
Note: The following example is used only for demonstrating the concept.
Use of Converter in WPF Application
Converters are used in WPF to convert the value of one data type to another. Or in simple language, Converter
(class inheriting IValueConverter
) accepts value in one format and returns the value in another format.
public class NumberToStringConverter : IValueConverter
{
}
In order to access this converter
, we declare a resource in XAML. E.g.
<Window.Resources>
<local:NumberToStringConverter x:Key="numConverter"></local:NumberToStringConverter>
</Window.Resources>
We then access this converter
in Binding
as follows:
<TextBox x:Name="txtBox1">100</TextBox>
<TextBox Text="{Binding Path=Text,Converter=
{StaticResource numConverter},ElementName=txtBox1}" >
This is a simple example demonstrating converter
usage. If we require converter
in different XAMLs, we repeat the above code in each one of them.
Now if you look carefully, this is redundant coding. We will end up having n number of instances of a converter
. Don't you think converter
s are meant to convert value of one type to other? So do we really require creating n number of instances of one converter
class?
Use of MarkupExtension with Singleton in Creating Converters
We can utilize the inbuilt feature of WPF to remove this redundancy. WPF provides MarkupExtension
to access your custom object in XAML. WPF MarkupExtension
allows us to write converters in an optimized way. Let’s see how.
In the above case, we can access the converter instance in XAML without creating its resource instance. To allow this, the Converter
has to be inherited from MarkupExtension
.
MarkupExtension
is an abstract
class defined by WPF Framework. We need to override ProvideValue
method. ProvideValue
method accepts variable of type IServiceProvider
(again a framework declared interface). We can use this method to return a singleton instance of Converter
as:
[MarkupExtensionReturnType(typeof(IValueConverter))]
public class NumberToStringConverterExtension: MarkupExtension, IValueConverter
{
private static NumberToStringConverterExtension _converter;
public override object ProvideValue(IServiceProvider serviceProvider)
{
if (_converter == null)
{
_converter = new NumberToStringConverterExtension();
}
return _converter;
}
#region IValueConverter Members
public object Convert(object value, Type targetType,
object parameter, System.Globalization.CultureInfo culture)
{
if (value == null)
{
return Binding.DoNothing;
}
return GetString(value);
}
public object ConvertBack(object value, Type targetType,
object parameter, System.Globalization.CultureInfo culture)
{
if (value != null && !string.IsNullOrEmpty(value.ToString()))
{
return GetInt(value);
}
return 0;
}
#endregion
private string GetString(object value)
{
return value.ToString();
}
private int GetInt(object value)
{
int val;
int.TryParse(value.ToString(), out val);
return val;
}
}
We can use this singleton instance in XAML as follows:
<TextBox x:Name="txtBox1">100
<TextBox Text="{Binding Path=Text,Converter=
{local:NumberToStringConverter},ElementName=txtBox1}">
Note: In the above code snippet, you can find that NumberToStringConverter
extension object is accessed without writing Extension
suffix.
Points of Interest
Inheriting converters with MarkupExtension
allows developers to access the Converter
directly in XAML without declaring it as Resource. Again as converter
s are used for generic activity, the instance can be made singleton restricting the user from creating more than one instance.
History
- First version - 14 April 2009 - Explains use of
MarkupExtension
to access Converter
as WPF extension