Совершенствуем xaml: Bindable Converters, Switch Converter, Sets

Нужно признать, xaml-код бывает отчасти многословным, что вызывает иногда некоторый дискомфорт при разработке. В статье рассмотрим оптимизации, которые помогут существенно улучшить организацию разметки и сделать её более читаемой. Особенно это касается работы с конвертерами, которые неотъемлемо связаны с механизмом привязки данных.Нам понадобятся некоторые знания из прошлых статей, в частности, понимание принципа прямых инжекций.7415d88d178848f6a1c93df00c75657c.jpgBindable Converters

Рано или поздно многие xaml-разработчики сталкивается с вопросом, возможно ли создать конвертер, поддерживающий привязку каких-либо параметров? Но даже если помимо реализации интерфейса IValueConverter, произвести наследование от класса DependencyObject и объявить в конвертере DependencyProperty, то привязка работать в большинстве случаев не станет, поскольку конвертер не является элементом визуального дерева! Конечно, возможно пойти ещё дальше и создать гибрид контрола-конвертера, незаметно помещаемого на представление, но такое экзотическое решения вряд ли можно назвать красивым, да и спектр его применения ограничен.

Но на выручку приходит принцип прямых инжекций, ведь ничто не мешает применить StoreBinding к Dependency Converter.

Всё гениальное просто! Отметим, что таким образом нельзя привязать конвертер к элементу визуального дерева, даже если они находятся на одном представлении. Но и такая проблема решаема, например, с помощью Attached Property у контрола и создания соответствующего расширения привязки.

Причём, такой вариант будет работать, даже если контрол и конвертер не находятся на одном представлении! Необходимо лишь быть осторожным с его реализацией, использовать для хранения слабую ссылку на контрол, чтобы не получилось утечек памяти.Switch Converter

Часто в больших проектах приходится создавать много различных однотипных классов-конвертеров, логика которых очень напоминает поведение операторов if-else и switch, например, для различных перечислений (Enums). Но на самом деле, в таких случаях достаточно ограничиться применением универсального Switch Converter:

Более того, свойства этого конвертера (в том числе конструкции Case) являются Dependency, то есть доступными для привязки с помощью StoreBinding! Кроме того, поддерживается Type Mode, когда ключом является не само значение объекта, а его тип: Получается, что такой конвертер запросто применим в качестве DataTemplateSelector даже там, где последний не поддерживается! Универсальность Switch Converter позволяет покрыть огромное число случаев, стоит только применить к нему немного фантазии. Global ResourcesРаз уж зашёл разговор о конвертерах, то стоит рассказать, как лучше всего организовать работу с ними. Прежде всего самые распространённые нужно вынести в отдельный словарь ресурсов:

После чего необходимо прямо или косвенно смержить этот словарь с ресурсами в App.xaml, что позволит использовать основные конвертеры практически в любых xaml-файлах приложения без дополнительных действий. Такое добавление в глобальные ресурсы приложения полезно производить для любых более-менее общих вещей: цветов, кистей, шаблонов и стилей, — что помогает очень просто реализовать, к примеру, механизмы смены тем в приложении. SetsОчень полезным приёмом является использование в xaml универсальной коллекции Set, применимой во множестве случаев. Она позволяет избежать «многоэтажных конструкций», вынести общие моменты и сделать разметку намного более аккуратной, а также передавать несколько аргументов в команду.

public class Set: ObservableCollection { } /Views/AnyView.xaml SecondParaneter