Статья будет посвящена простому, но эффективному паттерну — Composite Converter [составной конвертер].
Встречаются ситуации, когда уже есть несколько конвертеров, но возникает необходимость в создании нового, который является логической композицией имеющихся. Чтобы не создавать классов, которые отчасти дублируют функционал, можно поступить предложенным ниже образом. Обратите внимание на свойства PostConverter и PostConverterParameter.
using System.Windows.Data; namespace Aero.Converters.Patterns { public interface ICompositeConverter : IValueConverter { IValueConverter PostConverter { get; set; } object PostConverterParameter { get; set; } } }
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); } } }
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. Предыдущая статья о встраиваемых конвертерах
ссылка на оригинал статьи https://habrahabr.ru/post/276273/
Добавить комментарий