Хитрости Разработчика Xaml: Условный Преобразователь

Переключатель конвертера заслуживает особого внимания.

Простой и удобный, он обладает удивительной универсальностью.

На его основе легко построить множество распространенных типов конвертеров без объявления новых классов и прочего.

Не могу поверить — добро пожаловать!

Хитрости разработчика XAML: условный преобразователь

В процессе анализа средних и крупных проектов можно выявить важную закономерность — значительная часть классов преобразователей фактически содержит логику, эквивалентную конструкциям.

если еще , а также переключатель регистра по умолчанию .

Сразу возникает желание привести все к общему знаменателю, чтобы не создавать классы-близнецы, а сделать это не так уж и сложно.

ISwitchКонвертер

  
  
  
  
  
  
   

using System; using System.Collections.Generic; using System.Windows.Data; namespace Aero.Converters.Patterns { public class CaseSet : List<ICase> { public static readonly object UndefinedObject = new object(); } public interface ICase { object Key { get; set; } object Value { get; set; } Type KeyType { get; set; } } public interface ISwitchConverter : IValueConverter { CaseSet Cases { get; } object Default { get; set; } bool TypeMode { get; set; } } }

ICompositeConverter

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.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> <SwitchConverter x:Key="NumberSwitchConverter"> <Case Key="0" Value="Zero"/> <Case Key="1" Value="One"/> </SwitchConverter> </Grid.Resources> <TextBlock Text="{Binding Number, Converter={StaticResource NumberSwitchConverter}}"/> Number==0 => out: Zero Number==1 => out: One Number==2 => out: 2



<Grid.Resources> <SwitchConverter x:Key="NumberSwitchConverter" Default="Hello"> <Case Key="0" Value="Zero"/> <Case Key="1" Value="One"/> </SwitchConverter> </Grid.Resources> <TextBlock Text="{Binding Number, Converter={StaticResource NumberSwitchConverter}}"/> Number==0 => out: Zero Number==1 => out: One Number==2 => out: Hello

Он легко работает с числами, перечислениями, строками, логическими значениями, а также поддерживает цепная композиция .

Кроме того, у него есть еще один существенный бонус.

В WPF есть концепция Селекторы шаблонов , который не поддерживается, например, на Windows Phone Silverlight .

Если вы когда-нибудь им пользовались, то наверняка заметили не очень удобный момент — нужно создать С# -класс, откуда можно получить доступ не очень красивым способом XAML - Ресурсы.

Взгляни на пример из MSDN .

В действительности задачу селекторов шаблонов в большинстве реальных случаев очень легко свести к использованию обычных конвертеров, и единственное преимущество Выбор шаблона дополнительно обеспечивая доступ к контейнеру данных, к которому применяется шаблон.

Специально для таких сценариев Переключатель конвертера поддерживает специальный режим работы Тип Режим , где ключом к значению является тип объекта.



<SwitchConverter TypeMode="True" Default="{StaticResource DefaultDataTemplate}" x:Key="InfoConverter"> <Case KeyType="local:Person" Value="{StaticResource PersonDataTemplate}"/> <Case KeyType="local:PersonGroup" Value="{StaticResource PersonGroupDataTemplate}"/> </SwitchConverter>



<ListBox ItemsSource="{Binding Items}">

Теги: #XAML #mvvm #C++ #.

NET #wpf #silverlight #windowsphone #Ненормальное программирование #программирование #.

NET #Промышленное программирование

Вместе с данным постом часто просматривают:

Автор Статьи


Зарегистрирован: 2019-12-10 15:07:06
Баллов опыта: 0
Всего постов на сайте: 0
Всего комментарий на сайте: 0
Dima Manisha

Dima Manisha

Эксперт Wmlog. Профессиональный веб-мастер, SEO-специалист, дизайнер, маркетолог и интернет-предприниматель.