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

Posted

技术标签:

【中文标题】有没有办法在 XAML 中链接多个值转换器?【英文标题】:Is there a way to chain multiple value converters in XAML? 【发布时间】:2011-02-06 03:23:27 【问题描述】:

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

    反转一个范围内的值(例如,范围是 1 到 100;datacontext 中的值是 90;用户看到的值是 10) 将数字转换为字符串

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

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

如果我需要澄清这些,请告诉我。 :)

谢谢。

【问题讨论】:

【参考方案1】:

是的,有一些方法可以链接转换器,但它看起来并不漂亮,你在这里不需要它。如果你需要这个,问问自己这真的是要走的路吗?即使您必须编写自己的转换器,简单总是效果更好。

在您的特定情况下,您需要做的就是将转换后的值格式化为字符串。 Binding 上的 StringFormat 属性是您的朋友。

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

【讨论】:

如果你大量使用绑定,编写自定义转换器到链转换器最终会产生大量用于各种配置的愚蠢转换器。在这种情况下,接受的答案是一个很好的解决方案。【参考方案2】:

找到了我正在寻找的东西,感谢 Josh Smith:Piping Value Converters(archive.org link)。

他定义了一个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> 

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

【讨论】:

在此解决方案中,每个转换器必须只处理一种类型(必须在单值转换属性中声明)。 @Town 解决方案也可以处理多转换器。 请发布实现;否则,linkrot【参考方案3】:

我在 Silverlight 项目中使用了 Gareth Evans 的 this method。

这是我的实现:

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>

【讨论】:

最好,对于 ConvertBack 的实现来制作集合的副本并反转它,然后聚合它?所以 ConvertBack 将是 return this.Reverse&lt;IValueConverter&gt;().Aggregate(value, (current, converter) =&gt; converter.ConvertBack(current, targetType, parameter, culture)); @DLeh 这不是很优雅,因为它不起作用。它为所有转换器提供最终目标类型而不是正确的目标类型... 如何将 MultiValueConverter 用作第一个转换器? @Town 一位同事刚刚发现了这个问题,它让我再次查找它,为了怀旧。只是,我只是注意到您没有得到应得的评价(我接受了 我自己的 答案!),所以我现在已将您的答案标记为已接受。只晚了大约 9 年... :facepalm: @MalRoss 哈哈!谢谢!很高兴听到它仍然有用,我现在已经有 8 年没有接触过 Silverlight 了,但这仍然是我最受欢迎的答案 :)【参考方案4】:

Gareth Evans's Silverlight project 的Town's implementation 很好,但是它不支持不同的转换器参数。

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

转换器:

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>

【讨论】:

【参考方案5】:

这里是Town's answer 的一个小扩展,用于支持多绑定:

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

【讨论】:

以上是关于有没有办法在 XAML 中链接多个值转换器?的主要内容,如果未能解决你的问题,请参考以下文章

从 xaml 中清除 dependencyProperty 值

XAML 'NOT' 运算符?

有没有办法将元素链接转换为 XPath

Type Converters ,Markup Extensions,IValueConverter的区别

在 XAML 中使用布尔到颜色转换器

将 SQL 值从链接数据重新编码/转换为新列:为啥 CASE WHEN 返回多个值?