Найти тему

Привязки и конвертёры значений в WPF

Оглавление

Всем привет! Сегодня чуть-чуть углубимся в тему привязок в WPF и научимся делать довольно интересные штуки с нашими окнами в WPF-приложениях.

Я уже упоминал о привязках в статье о заполнении окна через ViewModel. Если кратко, привязка — это механизм, через который мы заполняем значениями наше окно и через который получаем их обратно во ViewModel после изменения пользователем. То есть мы не указываем прямо "в этом текстовом поле должно быть записано то-то", а говорим "в этом текстовом поле должно быть значение из ViewModel, свойство такое-то".

Окей, на базовом уровне понятно (а на не базовом лучше почитать здесь), но что, если мы совсем чуть-чуть отойдём в сторону? Например, захотим управлять видимостью какого-либо элемента через ViewModel (например, вывести сообщение "параметр не выбран", если параметр не выбран.

Э, да тут же всё просто, скажете вы. Создаём переменную IsVisible во VIewModel, делаем соответствующую привязку к видимости элемента...

Нет, так не работает, потому что за видимость отвечает перечисление Visibility, а не bool true/false. Окей, мы можем создать переменную типа Visibility и менять её значение в зависимости от того, хотим мы или не хотим видеть элемент. Но это уже, во-первых, перегружает ViewModel, а во-вторых, нарушает паттерн MVVM — ViewModel не должна знать, что мы видим, а что не видим, у неё другие задачи.

Конвертёры значений

И тут на помощь нам придут конвертёры значений. Я уже использовал их в своём шаблоне, но не рассказывал, зачем.

Итак, конвертёр — это специальный класс, который преобразует значения из одного типа в другой. Например, мы можем преобразовать видимость в boolean и обратно, или список в число элементов, или значение в цвет: что угодно во что угодно.

За примером обратимся к Revit Lookup — его исходный код находится в открытом доступе. Решим такую задачу для приложения, создание которого было примером в моём цикле статей про WPF: Если пользователь не выбрал параметр, то отобразим текст "Выберите параметр из списка для дальнейшей работы".

Как это работает: мы создадим TextBlock, передадим в его свойство Visibility ссылку на выбранный параметр, а в конвертёре напишем: если null, то вернуть Visibility.Visible, иначе Visibility.Collapsed.

Вот такой класс получается:

Обратите внимание:

  • Наследуем от MarkupExtension, IValueConverter.
  • Visibility берём из System.Windows, не из Autodesk.
  • В ProvideValue всегда возвращаем this.
  • В ConvertBack в данном случае ничего не делаем, так как привязка однонаправленная. Но иногда придётся и этот метод переопределять.

И чуть модифицируем наше окно:

-2

Чтобы размер окна менялся, удалим у окна свойство Height и добавим SizeToContent="Height".

Отлично, теперь мы научились создавать конвертёры. Давайте рассмотрим ещё один пример: в зависимости от типа хранения параметра изменим цвет окна: зелёный для текста, оранжевый для Integer и синий для Double.

Конвертёр "Значение в цвет"

Тут будет примерно тоже самое, но мы должны учитывать следующие моменты:

  • Объект привязки может быть равен null.
  • В конвертёр передаётся object и нам надо выполнить приведение к нужному типу.
  • Свойство Background — это Brush, поэтому нам надо создавать кисть, а не цвет.
  • Ошибка в привязке приведёт к вылету Ревита, что может доставить неудобства при отладке.

Получился вот такой код:

-3

В WIndow добавим такую строку:

Background="{Binding SelectedParameter,
Converter={utilities:ParameterColorConverter},
UpdateSourceTrigger=PropertyChanged}"

Результат:

-4

Тестирование и отладку данного проекта, как обычно, делаем через Addin-manager.

Заключение

Итоговый код, как обычно, у меня на GitHub. Подписывайтесь на мой телеграм-канал и не забывайте ставить звёздочки репозиторию. До новых встреч!

-5