Feedback

C# - Mehrere IValueConverter nacheinander anwenden

Veröffentlicht von am 3/8/2014
(0 Bewertungen)
Manchmal wäre es ganz praktisch im XAML mehrere Konverter auf eine Datenbindung einwirken zu lassen. Da das Standardmäßig nicht funktioniert, habe ich diese Klassen geschrieben. Man verwendet diese wie einen ganz normalen Konverter, dem man weitere Konverter übergibt. Siehe Beispielanwendung.

Benötigte Namespaces
System
System.Collections.ObjectModel
System.Globalization
System.Windows.Data
System.Windows.Markup
System.Linq

Getestete Plattformen
WPF mit .NET 4.5
Eine ähnliche Implementerung sollte auch unter Windows Store Apps, Windows Phone und Silverlight möglich sein. Dort unterscheiden sich eventuell einige Mitglieder von IValueConverter, sodass eine Anpassung nötig ist.

Hinweise
Den ValueConverter-Objekten kann man Eigenschaften zuweisen, die dann an die eigentlichen Konverter übergeben werden. So werden Konvertierungen mit verschiedenen Parametern usw. möglich. Das angeben von Eigenschaften wie TargetType ist nur bei Konvertern erforderlich, die diesen Parameter auch wirklich verwenden. Wird eine Eigenschaft nicht angegeben (so dass diese null ist), so wird dem Konverter der Parameter vom ValueConverterConnector übergeben.
Sollte ein Fehler wärend der Konvertierung auftreten, so wird der letzte Stand der Konvertierung zurück gegeben.

Beispielanwendung
Nachfolgender XAML-Code bindet die Visibility-Eigenschaft eines StackPanels an das ausgewählte Element einer ListBox. Dabei werden die 2 Konverter IsTypeConverter und BooleanToVisibilityConverter angewendet.
<StackPanel >
<StackPanel.Visibility>
<Binding Path="SelectedItem" ElementName="listBox1">
<Binding.Converter>
<l:ValueConverterConnector >
<l:ValueConverter Converter="{StaticResource IsTypeConverter}" Parameter="{x:Type l:ImageItemList}" TargetType="{x:Type s:Boolean}" />
<l:ValueConverter Converter="{StaticResource BooleanToVisibilityConverter}" TargetType="{x:Type Visibility}" />
</l:ValueConverterConnector>
</Binding.Converter>
</Binding>
</StackPanel.Visibility>
</StackPanel>
/// <summary>
/// Wendet mehrere Konverter auf eine Datenbindung an.
/// </summary>
[ContentProperty("Converters")]
public sealed class ValueConverterConnector : IValueConverter
{
    public ValueConverterConnector()
    {
        this.Converters = new ValueConverterCollection();
    }
    /// <summary>
    /// Ruft eine Liste mit Konvertern ab oder legt diese Fest.
    /// </summary>
    public ValueConverterCollection Converters { get; set; }

    #region IValueConverter Members

    /// <summary>
    /// Wendet alle Konverter auf einen Wert an.
    /// </summary>
    /// <param name="value">Der Wert auf den die Konverter angewendet werden sollen.</param>
    /// <param name="targetType">Der <c>targetType</c>-Parameter der an jeden Konverter übergeben werden soll, wenn dieser nicht selbst den Wert bereit stellt.</param>
    /// <param name="parameter">Der <c>parameter</c>-Parameter der an jeden Konverter übergeben werden soll, wenn dieser nicht selbst den Wert bereit stellt.</param>
    /// <param name="culture">Der <c>culture</c>-Parameter der an jeden Konverter übergeben werden soll, wenn dieser nicht selbst den Wert bereit stellt.</param>
    /// <returns><paramref name="value"/>, nachdem alle Konverter angewendet wurden.</returns>
    public object Convert(object value, Type targetType, object parameter, CultureInfo culture)
    {
        try
        {
            foreach (var converter in this.Converters)
            {
                value = converter.Converter.Convert(
                    value,
                    converter.TargetType == null ? targetType : converter.TargetType,
                    converter.Parameter == null ? parameter : converter.Parameter,
                    converter.Culture == null ? culture : converter.Culture);
            }
        }
        catch { }
        return value;
    }

    /// <summary>
    /// Wendet alle Umkehrungsfunktionen der Konverter auf einen Wert an.
    /// </summary>
    /// <param name="value">Der Wert auf den die Umkehrungsfunktionen der Konverter angewendet werden sollen.</param>
    /// <param name="targetType">Der <c>targetType</c>-Parameter der an jeden Konverter übergeben werden soll, wenn dieser nicht selbst den Wert bereit stellt.</param>
    /// <param name="parameter">Der <c>parameter</c>-Parameter der an jeden Konverter übergeben werden soll, wenn dieser nicht selbst den Wert bereit stellt.</param>
    /// <param name="culture">Der <c>culture</c>-Parameter der an jeden Konverter übergeben werden soll, wenn dieser nicht selbst den Wert bereit stellt.</param>
    /// <returns><paramref name="value"/>, nachdem alle Umkehrungsfunktionen der Konverter angewendet wurden.</returns>
    public object ConvertBack(object value, Type targetType, object parameter, CultureInfo culture)
    {
        try
        {
            foreach (var converter in this.Converters.Reverse())
            {
                value = converter.Converter.ConvertBack(
                    value,
                    converter.TargetType == null ? targetType : converter.TargetType,
                    converter.Parameter == null ? parameter : converter.Parameter,
                    converter.Culture == null ? culture : converter.Culture);
            }
        }
        catch { }
        return value;
    }

    #endregion
}
/// <summary>
/// Repräsentiert eine Liste mit <see cref="System.Windows.Data.IValueConverter"/>-Objekten.
/// </summary>
public sealed class ValueConverterCollection : Collection<ValueConverter> { }
/// <summary>
/// Stellt ein Konverter-Objekt mit zu übergebenden Parametern dar.
/// </summary>
public sealed class ValueConverter
{
    /// <summary>
    /// Ruft den Konverter ab oder legt diesen fest.
    /// </summary>
    public IValueConverter Converter { get; set; }
    /// <summary>
    /// Ruft den Konverter-Parameter ab oder legt diesen fest.
    /// </summary>
    public object Parameter { get; set; }
    /// <summary>
    /// Ruft ein <see cref="System.Globalization.CultureInfo"/>-Objekt ab oder legt eines fest, welches dem Konverter übergeben wird.
    /// </summary>
    public CultureInfo Culture { get; set; }
    /// <summary>
    /// Ruft den Zieltyp des Konvertierungsvorgangs ab oder legt diesen fest.
    /// </summary>
    public Type TargetType { get; set; }
}

Kommentare zum Snippet

 

Logge dich ein, um hier zu kommentieren!