Archive for the ‘Value Converters’ Category

Tips and Tricks: Making Value Converters More Accessible in Markup

Tuesday, March 17th, 2009

I recently had the pleasure of presenting some rather advanced WPF concepts (along with some cool tips and tricks) to a group of smart folks.  Unfortunately, I ran up against time constraints and was forced to drop the data binding portion of my talk.  I’m a little bummed about not being able to show one cool trick that I use a lot, so here it is…

Call me lazy (really, I’m okay with it), but I’ve never been wild about having to declare my value converters as resources before using them.  It’s just one extra step:

<Window.Resources>
  <src:MyConverter x:Key="MyConverter" />
</Window.Resources>

And then later the converter must be specified using a StaticResource reference, which incurs some overhead (albeit small overhead, in the grand scheme of things) for the resource resolution:

<TextBlock Text="{Binding SomePath, Converter={StaticResource MyConverter}}" />

I often choose to skip the middleman.  Instead of using the StaticResource markup extension to look up a converter, I simply derive my value converter, itself, from MarkupExtension.  Then I return an instance of it in the ProvideValue() override.

I have to assume there are plenty of others using this approach too.  (It’s clever, afterall, but that’s about the extent of the hyperbole I’d grant it.)  If you’re not one of them, I simply wanted to put it out there as a potential trick for your arsenal.

Below is a super simple example of a dummy converter (typically used to debug bindings) that does this:

public class DummyConverter : MarkupExtension, IValueConverter
{
    private static DummyConverter _converter = null;
    public override object ProvideValue(IServiceProvider serviceProvider)
    {
        if (_converter == null)
        {
            _converter = new DummyConverter();
        }
        return _converter;
    }
    #region IValueConverter Members
    public object Convert(object value, Type targetType, object parameter,
        CultureInfo culture)
    {
        return value; // set breakpoint here to debug your binding
    }

    public object ConvertBack(object value, Type targetType, object parameter,
        CultureInfo culture)
    {
        return value;
    }
    #endregion
}

The above class creates a singleton dummy converter that can be used across my app without any resource lookup.  The XAML usage is now simply this:

<TextBlock Text="{Binding SomePath, Converter={src:DummyConverter}}" />

This is much better, to my lazy way of thinking.

Can my value converter access the target of the binding?

Saturday, August 18th, 2007

Dear Dr. WPF,

In my application, I’m using a value converter to convert a GUID to a static resource.  The GUID is accessible in my DataTemplate through a binding like this:

<DataTemplate>
  <Grid Height="Auto" Width="Auto">
    <TextBlock Text="{Binding Path=ID}" />
  </Grid>
</DataTemplate>

I would really like to use the GUID in a more dynamic way as a key into a resource dictionary. I imagine it would look something like this (although obviously this won’t work): 

<DataTemplate>
  <Grid Height="Auto" Width="Auto">
    <ContentControl 
        Content="{StaticResource {Binding Path=ID}}" />
  </Grid>
</DataTemplate>

I thought I might be able to use a binding along with a value converter that uses FindResource() to look up the static resource. Unfortunately, my value converter does not receive a reference to the object on which the binding is set. It only gets the bound value (the GUID) and the type of the target dependency property. In order to call FindResource(), I need a reference to the actual target dependency object.

Is there an easy way to do this in WPF?

Thanks for any help you can provide!

Sincerely,
Jim
 


Hi Jim,

Yes, it can be frustrating that your value converter does not receive a reference to the target dependency object for the binding. Value converters were designed to be more generic in nature, allowing them to be used in scenarios that might not involve bindings. As such, they have no knowledge of the binding itself or the object on which it is set. That said, there are actually many cases where a value converter might desire this kind of contextual information. 

Your scenario is a prime candidate for a multibinding and multivalue converter. With a multibinding, you can actually supply your own reference to the target dependency object using one of the bindings, as follows:

<DataTemplate>
  <Grid>
    <ContentControl>
      <ContentControl.Content>
        <MultiBinding Converter="{StaticResource MyConverter}">
          <MultiBinding.Bindings>
            <Binding RelativeSource="{RelativeSource Self}" />
            <Binding Path="ID" />
          </MultiBinding.Bindings>
        </MultiBinding>
      </ContentControl.Content>
    </ContentControl>
  </Grid>
</DataTemplate>

 

In this case, the converter class must implement the IMultiValueConverter interface so that it can be used with the multibinding. Since we have conveniently passed in a Self reference as the first binding, we now have a reference to the target dependency object in our converter. The converter’s Convert method might look something like the following:

public object Convert(object[] values, Type targetType, 
    object parameter, CultureInfo culture)
{
  FrameworkElement targetObject = values[0] as FrameworkElement;
  if (targetObject == null)
  {
    return DependencyProperty.UnsetValue;
  }
  return targetObject.TryFindResource(values[1]);
}

 

I hope this helps!

Best regards,
Dr. WPF