Статья будет посвящена простому, но эффективному паттерну — Composite Converter [составной конвертер].
Встречаются ситуации, когда уже есть несколько конвертеров, но возникает необходимость в создании нового, который является логической композицией имеющихся. Чтобы не создавать классов, которые отчасти дублируют функционал, можно поступить предложенным ниже образом. Обратите внимание на свойства PostConverter и PostConverterParameter.
Это позволит объединять конвертеры в логические цепочки различной длины и запросто строить новые на базе существующих.
Гениальное просто! Пользуйтесь на здоровье!
Живые примеры доступны с библиотекой Aero Framework [резервная ссылка].
Спасибо!
P.S. Предыдущая статья о встраиваемых конвертерах
Встречаются ситуации, когда уже есть несколько конвертеров, но возникает необходимость в создании нового, который является логической композицией имеющихся. Чтобы не создавать классов, которые отчасти дублируют функционал, можно поступить предложенным ниже образом. Обратите внимание на свойства PostConverter и PostConverterParameter.
using System.Windows.Data;
namespace Aero.Converters.Patterns
{
public interface ICompositeConverter : IValueConverter
{
IValueConverter PostConverter { get; set; }
object PostConverterParameter { get; set; }
}
}
Inline Converter
using System;
using System.Globalization;
using System.Windows.Data;
using Aero.Converters.Patterns;
namespace Aero.Converters
{
public class InlineConverter : IInlineConverter, ICompositeConverter
{
public IValueConverter PostConverter { get; set; }
public object PostConverterParameter { get; set; }
public event EventHandler<ConverterEventArgs> Converting;
public event EventHandler<ConverterEventArgs> ConvertingBack;
public object Convert(object value, Type targetType, object parameter, CultureInfo culture)
{
var args = new ConverterEventArgs(value, targetType, parameter, culture);
var handler = Converting;
if (handler != null) handler(this, args);
return PostConverter == null
? args.ConvertedValue
: PostConverter.Convert(args.ConvertedValue, targetType, PostConverterParameter, culture);
}
public object ConvertBack(object value, Type targetType, object parameter, CultureInfo culture)
{
var args = new ConverterEventArgs(value, targetType, parameter, culture);
var handler = ConvertingBack;
if (handler != null) handler(this, args);
return PostConverter == null
? args.ConvertedValue
: PostConverter.ConvertBack(args.ConvertedValue, targetType, PostConverterParameter, culture);
}
}
}
Switch Converter
using System;
using System.Globalization;
using System.Linq;
using System.Windows;
using System.Windows.Data;
using System.Windows.Markup;
using Aero.Converters.Patterns;
namespace Aero.Converters
{
[ContentProperty("Cases")]
public class SwitchConverter : DependencyObject, ISwitchConverter, ICompositeConverter
{
public static readonly DependencyProperty DefaultProperty = DependencyProperty.Register(
"Default", typeof(object), typeof(SwitchConverter), new PropertyMetadata(CaseSet.UndefinedObject));
public SwitchConverter()
{
Cases = new CaseSet();
}
public object Default
{
get { return GetValue(DefaultProperty); }
set { SetValue(DefaultProperty, value); }
}
public CaseSet Cases { get; private set; }
public bool TypeMode { get; set; }
public object Convert(object value, Type targetType, object parameter, CultureInfo culture)
{
if (TypeMode) value = value == null ? null : value.GetType();
var pair = Cases.FirstOrDefault(p => Equals(p.Key, value) || SafeCompareAsStrings(p.Key, value));
var result = pair == null ? Default : pair.Value;
value = result == CaseSet.UndefinedObject ? value : result;
return PostConverter == null
? value
: PostConverter.Convert(value, targetType, PostConverterParameter, culture);
}
public object ConvertBack(object value, Type targetType, object parameter, CultureInfo culture)
{
if (TypeMode) value = value == null ? null : value.GetType();
var pair = Cases.FirstOrDefault(p => Equals(p.Value, value) || SafeCompareAsStrings(p.Value, value));
value = pair == null ? Default : pair.Key;
return PostConverter == null
? value
: PostConverter.ConvertBack(value, targetType, PostConverterParameter, culture);
}
private static bool SafeCompareAsStrings(object a, object b)
{
if (a == null && b == null) return true;
if (a == null || b == null) return false;
return string.Compare(a.ToString(), b.ToString(), StringComparison.OrdinalIgnoreCase) == 0;
}
public IValueConverter PostConverter { get; set; }
public object PostConverterParameter { get; set; }
}
}
Это позволит объединять конвертеры в логические цепочки различной длины и запросто строить новые на базе существующих.
<Grid.Resources>
<BooleanConverter x:Key="YesNoConverter" OnTrue="Yes" OnFalse="No"/>
<SwitchConverter x:Key="CompositeSwitchConverter" PostConverter="{StaticResource YesNoConverter}">
<Case Key="0" Value="False"/>
<Case Key="1" Value="True"/>
</SwitchConverter>
</Grid.Resources>
<TextBlock Text="{Binding Number, Converter={StaticResource CompositeSwitchConverter}}"/>
Number == 1 => out: Yes
Number == 0 => out: No
Гениальное просто! Пользуйтесь на здоровье!
Живые примеры доступны с библиотекой Aero Framework [резервная ссылка].
Спасибо!
P.S. Предыдущая статья о встраиваемых конвертерах