Click here to Skip to main content
Click here to Skip to main content

Use of MarkupExtension with Converters in WPF

, 14 Apr 2009 CPOL
Rate this:
Please Sign up or sign in to vote.
Optimize converters in WPF with MarkupExtension

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 converters and the optimum way of accessing the converters 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:

  1. Use of Converter in WPF 
  2. 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 converters 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)
    {
        //Some logic to convert int to string..
        return value.ToString();
    }
     private int GetInt(object value)
    {
       //Some logic to convert string to int..
       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 converters 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

License

This article, along with any associated source code and files, is licensed under The Code Project Open License (CPOL)

Share

About the Author

User-Rock
Software Developer
India India
No Biography provided

Comments and Discussions

 
GeneralAlternative approach PinmemberSevenate8-Jun-09 3:29 
GeneralMy vote of 2 PinmemberKjetil Klaussen20-Apr-09 21:49 
GeneralGood idea - except it is not a singleton Pinmembereug10c14-Apr-09 20:16 
GeneralRe: Good idea - except it is not a singleton PinmemberADumbProgrammer14-Apr-09 20:35 
GeneralRe: Good idea - except it is not a singleton Pinmembereug10c14-Apr-09 20:53 
GeneralRe: Good idea - except it is not a singleton PinmemberADumbProgrammer14-Apr-09 21:11 
GeneralRe: Good idea - except it is not a singleton Pinmembereug10c14-Apr-09 21:33 
Application.Resources are application wide - controls in other assemblies that use "{StaticResource key}" markup will search "locally" first, then eventually Application.Resources.
 
If your control library is accessed by multiple applications, you'll need to define such global resources in every App.xaml.
 
You can however create one or more ResourceDictionary in referenced assemblies - and use ResourceDictionary.MergedDictionaries to merge it with the Application.Resources. I do this for Converters, Styles, DataTemplates, Images etc.
GeneralThis link may be useful if you are formatting to string PinmemberLakshmipathy13-Apr-09 21:34 
GeneralRe: This link may be useful if you are formatting to string PinmemberADumbProgrammer14-Apr-09 3:22 

General General    News News    Suggestion Suggestion    Question Question    Bug Bug    Answer Answer    Joke Joke    Rant Rant    Admin Admin   

Use Ctrl+Left/Right to switch messages, Ctrl+Up/Down to switch threads, Ctrl+Shift+Left/Right to switch pages.

| Advertise | Privacy | Terms of Use | Mobile
Web04 | 2.8.141216.1 | Last Updated 15 Apr 2009
Article Copyright 2009 by User-Rock
Everything else Copyright © CodeProject, 1999-2014
Layout: fixed | fluid