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 NamespacesSystem
System.Collections.ObjectModel
System.Globalization
System.Windows.Data
System.Windows.Markup
System.Linq
Getestete PlattformenWPF 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.
HinweiseDen 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.
BeispielanwendungNachfolgender 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