Xaml: Call Binding Converter Without Defining StaticResource in Xaml Thanks to Markup Derived Base Class in C#

Posted by OmegaMan at September 9, 2013

Category: Silverlight, Windows 8, Windows Phone 8, WPF, Xaml

Tags: ,

When developing Xaml everyone has to create a converter in code at some point for binding data conversion. Of course to expose that converter to the Xaml bindings one has to specify it in as a static instantiated resource to be available to the binding call(s). In this post I demonstrate how to remove the middle man of that Xaml static instantiation to reside in a common base class which can be derived by the existing converters with minimal change. Once that is in place the converter will also be a MarkupExtension which can be called directly within the { } brackets such as shown on the highlighted line:

<Window xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
        xmlns:converters="clr-namespace:Omega.Operation.Converters"
        ...
        >

<DataGrid Grid.Row="1"
          Visibility="{Binding IsEditing, 
                       Converter={ converters:BooleanToVisibilityReverseConverter } 
                      }">
Convert the Converter

The change to any converter is quite minimal and once the base class (shown later) is in place it is simply a one line change. Here is the code for the converter used above.

The highlighted line shows the change;  simply adding the base class to its definition with a generic template of itself:

namespace Omega.Operation.Converters
{
/// <summary>Does the reverse where if a value is true the control is collapsed and if false the control is visibile</summary>
public class BooleanToVisibilityReverseConverter : CoverterBase<BooleanToVisibilityReverseConverter>, 
                                                   System.Windows.Data.IValueConverter
{
    public object Convert(object value, Type targetType, object parameter, System.Globalization.CultureInfo culture)
    {
        return (value is bool && (bool)value) ? Visibility.Collapsed : Visibility.Visible;
    }

    public object ConvertBack(object value, Type targetType, object parameter, System.Globalization.CultureInfo culture)
    {
        return value is Visibility && (Visibility)value == Visibility.Collapsed;
    }
}
}
Base Class Magic

The following generic base class will instantiate the derived class and return a single static instance of the derived class for usage in Xaml:

/// <summary>
/// This creates a Xaml markup which can allow converters (which inheirit form this class) to be called directly
/// without specify a static resource in the xaml markup.
/// </summary>
public  class CoverterBase<T> : MarkupExtension where T : class, new()
 {
    private static T _converter = null;

    public CoverterBase() { }

    /// <summary>Create and return the static implementation of the derived converter for usage in Xaml.</summary>
    /// <returns>The static derived converter</returns>
    public override object ProvideValue(IServiceProvider serviceProvider)
    {
        return _converter ?? (_converter = (T) Activator.CreateInstance(typeof (T), null));
    }
}

With the base class providing the required implementation of for the MarkupExtension, the derived class can be simply called in the Xaml and avoiding having to use the static resource implementation.

Things to Consider
  • Works in WPF, Silverlight, Windows Phone 8 (WP8), and Windows 8 Store apps.
  • Visual Studio’s Xaml designer may give blue squiggly warning “No constructor type for ‘xxx’ has 0 parameters.”. Ignore that warning…for there is a default constructor which doesn’t have to be defined in C#.
Share

4 Comments

  1. adma says

    I would add the new() constraint to your T type, because you require such a constructor, don’t you? Then the Activator.CreateInstance(typeof (T), null)) method should never fail.

    Reply
    • OmegaMan says

      Thanks Adma…its the little things one overlooks. I added your suggestion to the above example code.

      Reply
  2. Jerry Nixon says

    Very clever code. Very clever and very useful for developers who will take the 30 seconds to understand what you are proposing. Like normal, Bill, great work. //Jerry

    Reply
  3. Andrew says

    This broke down when I tried to use it in multiple places. Specifically, I use it as prescribed above to control a Window property. I also use the same type as normal in a ResourceDictionary. In the ResourceDictionary I have to change the behavior of specific instances of the converter by setting property values on those instances. In this implementation, there is only one instance. Others get created, but never used (shrug). To fix this I change the implementation of ProvideValue to just:

    { return this; }

    and I remove the _instance member.

    Reply

Leave a comment

(required)
(required) (will not be published)

This site uses Akismet to reduce spam. Learn how your comment data is processed.