¿Hay alguna manera de encadenar varios convertidores de valor en XAML?


Tengo una situación en la que necesito mostrar un valor entero, vinculado a una propiedad en mi contexto de datos, después de ponerlo a través de dos conversiones separadas:

  1. Invierta el valor dentro de un rango (por ejemplo, el rango es de 1 a 100; el valor en datacontext es 90; el usuario ve un valor de 10)
  2. convierte el número en una cadena

Me doy cuenta de que podría hacer ambos pasos creando mi propio convertidor (que implementa IValueConverter). Sin embargo, ya tengo un convertidor de valor separado eso hace solo el primer paso, y el segundo paso está cubierto por Int32Converter.

¿Hay alguna forma de encadenar estas dos clases existentes en XAML sin tener que crear otra clase que las agregue?

Si necesito aclarar esto, por favor hágamelo saber. :)

Gracias.

Author: kpozin, 2010-04-09

4 answers

Usé este método de Gareth Evans en mi proyecto Silverlight.

Aquí está mi implementación:

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
}

Que luego se puede usar en XAML de esta manera:

<c:ValueConverterGroup x:Key="InvertAndVisibilitate">
   <c:BooleanInverterConverter/>
   <c:BooleanToVisibilityConverter/>
</c:ValueConverterGroup>
 174
Author: Town,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2017-05-02 15:30:00

Encontré exactamente lo que estaba buscando, cortesía de Josh Smith: Convertidores de valor de tuberías (archive.org link).

Él define una clase ValueConverterGroup, cuyo uso en XAML es exactamente como yo esperaba. He aquí un ejemplo:

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

Gran material. Gracias, Josh. :)

 52
Author: Mal Ross,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2015-09-07 12:12:04

Sí, hay formas de encadenar convertidores, pero no se ve bonito y no lo necesita aquí. Si alguna vez llega a necesitar esto, pregúntese es que realmente el camino a seguir? Simple siempre funciona mejor incluso si tiene que escribir su propio convertidor.

En su caso particular, todo lo que necesita hacer es formatear un valor convertido en una cadena. StringFormat propiedad en un Binding es su amigo aquí.

 <TextBlock Text="{Binding Value,Converter={StaticResource myConverter},StringFormat=D}" />
 6
Author: wpfwannabe,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2010-04-24 09:33:33

La implementación de Town de el proyecto Silverlight de Gareth Evans es excelente, sin embargo, no admite diferentes parámetros del convertidor.

Lo modifiqué para que pueda proporcionar parámetros, delimitados por comas (a menos que los escape, por supuesto).

Convertidor:

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

Nota: ConvertBack no está implementado aquí, ver mi Gist para la versión completa.

Aplicación:

<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>
 4
Author: Trevi Awater,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2018-08-30 07:48:39