Эстетика XAML: конвертеры значений
В статье представлены обобщённые подходы применения конвертеров значений при написании XAML-кода.

IValueConverterData BindingXAMLWPFUWPXamarin FormsUISwitchConverterKeyToValueConverterInlineConverterAggregateConverterResourceDictionary
Конвертеры значений совместно с механизмом привязки данных являются важными компонентами в разработке пользовательских интерфейсов на основе XAML. Конвертеры значений подразумевают наличие логики, помещенной в отдельный класс, реализующий интерфейс IValueConverter. Обычно имя класса отражает функциональное назначение, а сами экземпляры декларируются в разметке.
Switch Converter & Key To Value Converter
На практике многие конвертеры значений имеют тривиальную логику схожую по структуре с тернарным оператором (?:) или конструкциям if-else, switch-case-default. Однако существуют обобщенные шаблоны KeyToValueConverter и SwitchConverter, которые позволяют избежать добавления в проект однотипных по структуре классов путём декларирования логических значений и ветвлений непосредственно в разметке.
Концепция
Применение
KeyToValueConverter — проверяет входное значение на соответствие со значением из свойства Key, если соответствие выполнено, то в качестве выходного берётся значение из свойства Value, в противном случае из свойства ByDefault.
SwitchConverter — выполняет поиск первого соответствующего Case из списка по его ключу из свойства Key, если соответствующий Case найден, то берётся заданное в нём значение из свойства ¨C31C, в противном случае из свойства¨C90C¨C32C, заданного в самом конвертере значений.
Если свойство Value или ByDefault явно не задано, но выполняется соответствующее ему условие, то в таком случае происходит обыкновенный проброс входного значения в качестве выходного.
Также у KeyToValueConverter иногда полезно задавать ключ в ConverterParameter через свойство KeySource
Для особых случаев у KeySource возможны четыре режима работы:
Manual (by default) — в качестве ключа при проверке соответствия всегда используется значение из свойства Key либо выполняется проброс значения, когда оно не задано
ConverterParameter — в качестве ключа всегда используется значение из свойства привязки ConverterParameter либо выполняется проброс значения, когда оно не задано
PreferManual — если manual Key явно задан, то он имеет приоритет перед ConverterParameter
PreferConverterParameter — если ConverterParameter явно задан, то он имеет приоритет перед manual Key
Стоит также отметить, что у SwitchConverter помимо обычных Case доступны также TypedCase, основное отличие которых в проверке на соответствие по типу значения
Иногда возникает необходимость продебажить работу конвертера значений. Для этой цели у SwitchConverter предусмотрено свойство DiagnosticKey, если оно задано, то при срабатывании привязки данных в Trace будут выводится диагностические сообщения следующего формата
var diagnosticMessage = matchedCase.Is()
? $"{DiagnosticKey}: '{matchedValue}' matched by key '{matchedCase.Key}' for '{value}' and converted to '{convertedValue}'"
: $"{DiagnosticKey}: The default value '{matchedValue}' matched for '{value}' and converted to '{convertedValue}'";
Trace.WriteLine(diagnosticMessage);
...
Dependency Value Converter
Также свойства Key, Value и ByDefault полезно объявлять в качестве свойств зависимости (Dependency Properties), то есть наследовать конвертеры и Cases от класса DependencyObject. Хотя конвертеры значений обычно не являются элементами визуального дерева, что отчасти ограничивает работу механизма привязки данных, тем не менее остаётся возможность производить привязку к статическим ресурсам или наследникам класса Binding, например
Inline Converter
Встраиваемый конвертер позволят перенести логику по преобразованию значений из отдельного класса, реализующего интерфейс IValueConverter, в code-behind класс конкретного представления на основе событийной модели.
Это позволяет получить доступ к представлению и его отдельным визуальным элементам из логики конвертирования при реализации сложных сценариев, которые затруднительно реализовать при классическом подходе.
Для этого необходимо добавить декларацию конвертера в разметку, а code-behind классе определить обработчики для соответствующих событий Converting и ConvertingBack
private void InlineConverter_OnConverting(object sender, ConverterEventArgs e)
{
// e.Value - access to input value
// this.DataContext - access to Data Context or another properties of the view
// access to child visual elements of this root view
e.ConvertedValue = // set output value
$"DataContext: {DataContext}, Converter Value: {e.Value}";
}
private void InlineConverter_OnConvertingBack(object sender, ConverterEventArgs e)
{
// ...
}
Aggregate Converter
Агрегирующий конвертер предназначен для объединения конвертеров в цепочки, при этом преобразование значения происходит последовательно в порядке декларирования вложенных конвертеров.
App.xaml
Обобщённые конвертеры значений полезно помещать в отдельный Resource Dictionary, а затем мержить их в качестве глобальных ресурсов в файл App.xaml. Это позволяет переиспользовать конвертеры значений в различных представлениях без их повторного декларирования.
...
Ace Framework
Примеры реализации представленных конвертеров можно найти в библиотеке Ace Framework gitlab bitbucket
С благодарностью за внимание и интерес!
