Is there a way to chain multiple value converters in XAML?

Found exactly what I was looking for, courtesy of Josh Smith: Piping Value Converters (archive.org link).

He defines a ValueConverterGroup class, whose use in XAML is exactly as I was hoping for. Here's an example:

<!-- Converts the Status attribute text to a SolidColorBrush used to draw 
     the output of statusDisplayNameGroup. -->
<local:ValueConverterGroup x:Key="statusForegroundGroup">
  <local:IntegerStringToProcessingStateConverter  />
  <local:ProcessingStateToColorConverter />
  <local:ColorToSolidColorBrushConverter />
</local:ValueConverterGroup> 

Great stuff. Thanks, Josh. :)


I used this method by Gareth Evans in my Silverlight project.

Here's my implementation of it:

public class ValueConverterGroup : List<IValueConverter>, IValueConverter
{
    #region IValueConverter Members

    public object Convert(object value, Type targetType, object parameter, System.Globalization.CultureInfo culture)
    {
        return this.Aggregate(value, (current, converter) => converter.Convert(current, targetType, parameter, culture));
    }

    public object ConvertBack(object value, Type targetType, object parameter, System.Globalization.CultureInfo culture)
    {
        throw new NotImplementedException();
    }

    #endregion
}

Which can then be used in XAML like this:

<c:ValueConverterGroup x:Key="InvertAndVisibilitate">
   <c:BooleanInverterConverter/>
   <c:BooleanToVisibilityConverter/>
</c:ValueConverterGroup>

Town's implementation of Gareth Evans's Silverlight project is great, however it does not support different converter parameters.

I modified it so you can provide parameters, comma delimited (unless you escape them of course).

Converter:

public class ValueConverterGroup : List<IValueConverter>, IValueConverter
{
    private string[] _parameters;

    public object Convert(object value, Type targetType, object parameter, System.Globalization.CultureInfo culture)
    {
        if(parameter != null)
            _parameters = Regex.Split(parameter.ToString(), @"(?<!\\),");

        return (this).Aggregate(value, (current, converter) => converter.Convert(current, targetType, GetParameter(converter), culture));
    }

    public object ConvertBack(object value, Type targetType, object parameter, System.Globalization.CultureInfo culture)
    {
        throw new NotImplementedException();
    }

    private string GetParameter(IValueConverter converter)
    {
        if (_parameters == null)
            return null;

        var index = IndexOf(converter as IValueConverter);
        string parameter;

        try
        {
            parameter = _parameters[index];
        }

        catch (IndexOutOfRangeException ex)
        {
            parameter = null;
        }

        if (parameter != null)
            parameter = Regex.Unescape(parameter);

        return parameter;
    }
}

Note: ConvertBack is not implemented here, see my Gist for the full version.

Implementation:

<ContentPage xmlns="http://xamarin.com/schemas/2014/forms" xmlns:x="http://schemas.microsoft.com/winfx/2009/xaml" xmlns:converters="clr-namespace:ATXF.Converters;assembly=ATXF" x:Class="ATXF.TestPage">
  <ResourceDictionary>
    <converters:ValueConverterGroup x:Key="converters">
      <converters:ConverterOne />
      <converters:ConverterTwo />
    </converters:ValueConverterGroup>
  </ResourceDictionary>
  
  <Label Text="{Binding InitialValue, Converter={StaticResource converters}, ConverterParameter='Parameter1,Parameter2'}" />
</ContentPage>

Yes, there are ways to chain converters but it does not look pretty and you don't need it here. If you ever come to need this, ask yourself is that really the way to go? Simple always works better even if you have to write your own converter.

In your particular case, all you need to do is format a converted value to a string. StringFormat property on a Binding is your friend here.

 <TextBlock Text="{Binding Value,Converter={StaticResource myConverter},StringFormat=D}" />