Всем привет! Сегодня чуть-чуть углубимся в тему привязок в 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.
Вот такой класс получается:
Обратите внимание:
- Visibility берём из System.Windows, не из Autodesk.
- В ProvideValue всегда возвращаем this.
- В ConvertBack в данном случае ничего не делаем, так как привязка однонаправленная. Но иногда придётся и этот метод переопределять.
И чуть модифицируем наше окно:
Чтобы размер окна менялся, удалим у окна свойство Height и добавим SizeToContent="Height".
Отлично, теперь мы научились создавать конвертёры. Давайте рассмотрим ещё один пример: в зависимости от типа хранения параметра изменим цвет окна: зелёный для текста, оранжевый для Integer и синий для Double.
Конвертёр "Значение в цвет"
Тут будет примерно тоже самое, но мы должны учитывать следующие моменты:
- Объект привязки может быть равен null.
- В конвертёр передаётся object и нам надо выполнить приведение к нужному типу.
- Свойство Background — это Brush, поэтому нам надо создавать кисть, а не цвет.
- Ошибка в привязке приведёт к вылету Ревита, что может доставить неудобства при отладке.
Получился вот такой код:
В WIndow добавим такую строку:
Background="{Binding SelectedParameter,
Converter={utilities:ParameterColorConverter},
UpdateSourceTrigger=PropertyChanged}"
Результат:
Тестирование и отладку данного проекта, как обычно, делаем через Addin-manager.
Заключение
Итоговый код, как обычно, у меня на GitHub. Подписывайтесь на мой телеграм-канал и не забывайте ставить звёздочки репозиторию. До новых встреч!