有没有办法在XAML中链接多个值转换器?


123

在经过两次单独的转换后,我需要显示一个整数值,该值绑定到我的数据上下文中的属性:

  1. 反转某个范围内的值(例如,范围是1到100;数据上下文中的值是90;用户看到的值是10)
  2. 将数字转换为字符串

我意识到我可以通过创建自己的转换器(实现IValueConverter)来完成这两个步骤。但是,我已经有一个单独的值转换器,它仅执行第一步,而第二步由Int32Converter覆盖。

有没有一种方法可以在XAML中链接这两个现有类而不必创建进一步的类来聚合它们?

如果我需要澄清其中任何一个,请告诉我。:)

谢谢。

Answers:


198

我在Silverlight项目中使用了Gareth Evans的这种方法

这是我的实现:

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
}

然后可以在XAML中像这样使用它:

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

3
对于ConvertBack的实现来说,最好是制作该集合的副本并对其进行反转,然后对该集合进行汇总?因此,ConvertBack将是return this.Reverse<IValueConverter>().Aggregate(value, (current, converter) => converter.ConvertBack(current, targetType, parameter, culture));
Nick Udell,2014年

5
@DLeh这不是很优雅,因为它不起作用。它为所有转换器提供最终目标类型,而不是正确的目标类型...
Aleksandar Toplek

如何将它与MultiValueConverter一起用作第一个Converter?
LightMonk

1
@Town一位同事刚刚发现了这个问题,出于怀旧的缘故,它使我再次查找它。只是,我只是注意到您没有得到应得的荣誉(我接受了我自己的答案!),所以我现在将您的答案标记为接受。仅晚了大约9年...:facepalm:
马尔·罗斯

@MalRoss哈哈!谢谢!很好听,它仍然是有用的,我没碰过,现在的Silverlight有关这些年的8,但这个仍然是我最普遍的回答:)

54

准确地找到了我想要的东西,这由Josh Smith:Piping Value Converters (archive.org链接)提供

他定义了一个ValueConverterGroup类,该类在XAML中的用途与我所希望的完全相同。这是一个例子:

<!-- 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> 

好东西。谢谢,乔希。:)


2
在此解决方案中,每个转换器只能处理一种类型(必须在single-ValueConversion-attribute中声明)。@Town解决方案也可以应对多转换器。
Y. Shoham

9
请发布实施;否则,linkrot
杰克·伯杰

9

TownGareth Evans的Silverlight项目的实施效果很好,但是它不支持不同的转换器参数。

我对其进行了修改,以便您可以提供以逗号分隔的参数(当然,除非您转义了它们)。

转换器:

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;
    }
}

注意:此处未实现ConvertBack ,有关完整版本,请参阅我的Gist

实现方式:

<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>

6

是的,有很多方法可以链接转换器,但是它看起来并不漂亮,而且您在这里不需要。如果您曾经需要此功能,请问自己这是真的吗?即使必须编写自己的转换器,Simple总是可以更好地工作。

在您的特定情况下,您要做的就是将转换后的值格式化为字符串。StringFormat的物业Binding是您的朋友在这里。

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

5
如果您大量使用绑定,则将自定义转换器写入链式转换器最终会导致大量笨拙的转换器用于各种配置。在这种情况下,可接受的答案是一个很好的解决方案。
JacekGorgoń2013年

0

这是Town支持多绑定的答案的一小部分扩展:

public class ValueConverterGroup : List<IValueConverter>, IValueConverter, IMultiValueConverter
{
    #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();
    }

    public object Convert(object[] values, Type targetType, object parameter, CultureInfo culture)
    {
        return Convert(values as object, targetType, parameter, culture);
    }

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

    #endregion
}
By using our site, you acknowledge that you have read and understand our Cookie Policy and Privacy Policy.
Licensed under cc by-sa 3.0 with attribution required.