Переключатель конвертера заслуживает особого внимания.
Простой и удобный, он обладает удивительной универсальностью.
На его основе легко построить множество распространенных типов конвертеров без объявления новых классов и прочего.
Не могу поверить — добро пожаловать!
В процессе анализа средних и крупных проектов можно выявить важную закономерность — значительная часть классов преобразователей фактически содержит логику, эквивалентную конструкциям.
если еще , а также переключатель регистра по умолчанию .
Сразу возникает желание привести все к общему знаменателю, чтобы не создавать классы-близнецы, а сделать это не так уж и сложно.
ISwitchКонвертер
ICompositeConverterusing 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; } } }
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 #Промышленное программирование
-
Вольф, Макс
19 Oct, 24 -
Добавьте Вложение К Своему Резюме
19 Oct, 24 -
Хотели Бы Вы Пойти В Такие Кинотеатры?
19 Oct, 24 -
Живая Игра Без Графики
19 Oct, 24