2010-04-09 18 views
105

Ich habe eine Situation geraten, in der ich brauche einen Integer-Wert, auf eine Eigenschaft auf meinem Datenkontext gebunden zu zeigen, nachdem sie durch zwei getrennte Umwandlungen setzen:Gibt es eine Möglichkeit, mehrere Wertkonverter in XAML zu verketten?

  1. den Wert innerhalb eines Bereichs umkehren (zB Bereich 1 bis 100; Wert in Datacontext ist 90; Benutzer sehen Wert von 10)
  2. die Zahl in einen String

ich weiß, konvertieren ich (das implementiert IValueConverter) meinen eigenen Konverter, indem beide Schritte tun kann. Allerdings habe ich bereits einen separaten Wertkonverter, der nur den ersten Schritt erledigt, und der zweite Schritt wird von Int32Converter abgedeckt.

Gibt es eine Möglichkeit, diese beiden vorhandenen Klassen in XAML zu verketten, ohne eine weitere Klasse zu erstellen, die sie aggregiert?

Wenn ich etwas davon klären muss, lass es mich wissen. :)

Danke.

Antwort

50

genau gefunden, was ich für, mit freundlicher Genehmigung von Josh Smith war auf der Suche: Piping Value Converters(archive.org link).

Er definiert eine ValueConverterGroup Klasse, deren Verwendung in XAML ist genau so, wie ich es mir erhofft hatte. Hier ist ein Beispiel:

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

Tolle Sachen. Danke, Josh. :)

+1

Bei dieser Lösung muss jeder Konverter nur mit einem Typ arbeiten (er muss im single-ValueConversion-Attribut deklariert sein). @Town-Lösung kann auch mit Multiconverter umgehen. –

+5

posten Sie bitte die Implementierung; andernfalls, linkrot –

4

Ja, es gibt Möglichkeiten, um Konverter zu ketten, aber es sieht nicht hübsch aus und Sie brauchen es hier nicht. Wenn Sie jemals das brauchen, fragen Sie sich, ist das wirklich der Weg zu gehen? Simple funktioniert immer besser, auch wenn Sie einen eigenen Konverter schreiben müssen.

In Ihrem speziellen Fall müssen Sie lediglich einen konvertierten Wert in eine Zeichenfolge formatieren. StringFormat Eigenschaft auf einer Binding ist dein Freund hier.

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

wird die Arbeit in TwoWay String? – diimdeep

+2

Wenn Sie Bindungen stark verwenden, endet das Schreiben von benutzerdefinierten Konvertern in Kettenkonvertern mit vielen doofen Konvertern für alle Arten von Konfigurationen. In diesem Fall ist die angenommene Antwort eine wunderbare Lösung. –

165

Ich verwendete this method von Gareth Evans in meinem Silverlight-Projekt.

Hier ist meine Implementierung davon:

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 
} 

die dann in XAML wie folgt verwendet werden kann:

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

Ist es am besten, für eine Implementierung von ConvertBack eine Kopie der Sammlung zu erstellen, sie umzukehren und dann über diese zu aggregieren? Das ConvertBack wäre also 'return this.Reverse (). Aggregate (Wert, (current, converter) => converter.ConvertBack (current, targetType, Parameter, culture));' –

+5

@DLeh Das ist nicht wirklich elegant wie es nicht funktioniert. Es bietet allen Konvertern den endgültigen Zieltyp anstelle des korrekten Zieltyps ... –

+0

Dies funktioniert auch in UWP, yay! –

0

Town's implementation von Gareth Evans's Silverlight project ist groß, aber es nicht anders Konverter Parameter unterstützen.

Ich habe es so geändert, dass Sie Parameter bereitstellen können, die durch Kommas getrennt sind (außer Sie entgehen ihnen natürlich).

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

Hinweis: ConvertBack ist hier nicht implementiert, siehe meine Gist für eine aktualisierte Version.

Umsetzung:

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