Wednesday 25 April 2012

Binding Converter Parameters to StaticResources

Here is the bad news, you can’t but here’s the good news, using a bit of jiggery pokery you can easily work around it!

Scenario

image

I had a view containing three ellipses that I wanted to colour based on a property for their data context.  The expected result was blue if the value was zero, red if the value was greater than zero and yellow if something went wrong.

The Obvious Approach Doesn’t Work

I had my colours set in my UserControl.Resources so I would like to have used the following code:

<UserControl.Resources>
<SolidColorBrush x:Name="ZeroBrush" Color="SteelBlue" />
<SolidColorBrush x:Name="OverZeroBrush" Color="Red" />
</UserControl.Resources>

<Ellipse Fill="{Binding Path=Count,
Converter={converters:CountToBrushConverter
ZeroBrush={StaticResource ZeroBrush},
OverZeroBrush={StaticResource OverZeroBrush}}}" />
public class CountToBrushConverter : MarkupExtension, IMultiValueConverter
{
private static CountToBrushConverter _converter;
private readonly SolidColorBrush INCORRECT_USAGE_OF_CONVERTER = new SolidColorBrush(Color.FromArgb(255, 255, 255, 0));

public SolidColorBrush ZeroBrush { get; set; }
public SolidColorBrush OverZeroBrush { get; set; }

public object Convert(object[] values, Type targetType, object parameter, CultureInfo culture)
{
int count;
if (!Int32.TryParse(values[0].ToString(), out count)) return INCORRECT_USAGE_OF_CONVERTER;

return count == 0 ? ZeroBrush : OverZeroBrush;
}

public object[] ConvertBack(object value, Type[] targetTypes, object parameter, CultureInfo culture)
{
throw new NotImplementedException();
}

public override object ProvideValue(IServiceProvider serviceProvider)
{
return _converter ?? (_converter = new CountToBrushConverter());
}
}

The problem with this approach is that the value converter properties are not dependency objects and therefore cannot have a binding assigned to them.


The Solution


Swap your IValueConverter for an IMultiValueConverter and use an implementation of the multi-binding approach from WPF. 

<Ellipse Fill="{xaml:MultiBinding Converter={converters:CountToBrushConverter}, 
Source1={Binding Path=Count},
Source2={StaticResource ZeroBrush},
Source3={StaticResource OverZeroBrush}}" />
public class CountToBrushConverter : MarkupExtension, IMultiValueConverter
{
private static CountToBrushConverter _converter;
private readonly SolidColorBrush INCORRECT_USAGE_OF_CONVERTER = new SolidColorBrush(Color.FromArgb(255, 255, 255,0));

/// <summary>
/// Returns a SolidBrushColour based on whether the count = 0 or not
/// </summary>
/// <param name="values">Array of objects: value[0] = Count, value[1] = ZeroBrush, value[2] = OverZeroBrush</param>
/// <param name="targetType">Not used.</param>
/// <param name="parameter">Not used.</param>
/// <param name="culture">Not used.</param>
/// <returns>SolidBrushColor</returns>
public object Convert(object[] values, Type targetType, object parameter, CultureInfo culture)
{
if (values == null || values.Length != 3) return INCORRECT_USAGE_OF_CONVERTER;

int count;
if (!Int32.TryParse(values[0].ToString(), out count)) return INCORRECT_USAGE_OF_CONVERTER;

var zeroBrush = values[1] as SolidColorBrush;
if (zeroBrush == null) return INCORRECT_USAGE_OF_CONVERTER;

var overZeroBrush = values[2] as SolidColorBrush;
if (overZeroBrush == null) return INCORRECT_USAGE_OF_CONVERTER;

return count == 0
? zeroBrush
: overZeroBrush;
}

public object[] ConvertBack(object value, Type[] targetTypes, object parameter, CultureInfo culture)
{
throw new NotImplementedException();
}

public override object ProvideValue(IServiceProvider serviceProvider)
{
return _converter ?? (_converter = new CountToBrushConverter());
}
}

Multi Bindings for Silverlight


Henrik Jonsson has an implementation on Code Project:
http://www.codeproject.com/Articles/286171/MultiBinding-in-Silverlight-5

Colin Eberhardt has another option on his blog:
http://www.scottlogic.co.uk/blog/colin/2010/05/silverlight-multibinding-solution-for-silverlight-4/

You can download a zip of the version I used:
http://stevenhollidge.com/blog-source-code/MultiBinding.zip

No comments:

Post a Comment