В этой статье так же рассмотрим следующие темы:
- Создание команды с параметром
- Привязка с RelativeSource, изменение DataContext во вложенных объектах окна
- Добавление SVG-иконок в окно.
Задача
Напишем простейший менеджер общих параметров. Он будет выводить таблицу с указанием Id и имени каждого общего параметра, и будет кнопка для удаления этого параметра.
Дисклеймер: Статья написана в учебных целях. Не надо брать и удалять все подряд общие параметры. Удалённый общий параметр пропадёт из всех семейств и спецификаций проекта, и его ручное добавление ничего не вернёт. Будьте аккуратны.
Решение
Я продолжу работать в своем проекте WPFApplication. Там используется Community.Toolkit.Mvvm. Как с ней работать, описано здесь. Если вам вообще непонятно, что происходит, читайте всю подборку про WPF.
Создам новую папку, и следующие файлы:
А также наконец-то добавлю Application и addin-файл, чтобы приложение можно было запустить с панели Ревита, а не через addin-менеджер.
Код ViewModel и Descriptor будет очень простым:
Обратите внимание, что тут мы передаём в команду параметр и даже типизируем его. Это важно, мы будем это использовать во View.
Окно
Самое интересное у нас будет в XAML-коде.
Я хочу сделать вот такое окно:
Но как сделать кнопку с такой иконкой?
- Найдём иконку в svg-формате.
- Скачаем её и откроем в блокноте.
- Скопируем в контент кнопки вот этот path и обернём его в xaml во ViewBox:
А в xaml поменяем path на Path и d на Data, и добавим цвет:
Готово, картинку добавили.
DataGrid
Теперь разберёмся с тем, как создать таблицу с данными. Тут нам поможет DataGrid. В принципе, нам даже не обязательно её заполнять колонками, а достаточно передать ItemSource, а колонки появятся сами по свойствам элементов, составляющих ItemSource. Но я предпочитаю явно указывать колонки. Получилось так:
Мы создали 2 обычных текстовых колонки и одну колонку с кнопкой, переопределив её DataTemplate (мы уже разбирали что-то подобное). Переопределить шаблон можно так, как нам угодно — в данном случае мы сделали просто кнопку с картинкой, повесив на ней команду и передав Dexcriptor, являющийся контекстом данных строки, в качестве параметра.
Нюансы привязок и RelativeSourse
Теперь разберёмся, почему такие странные привязки в 25-27 строках. Дело в том, что когда мы попадаем внутрь элемента с ItemSource, контекстом данных для вложенных элементов становятся составляющие ItemSource объекты. То есть теперь для кнопки контекст данных — это SharedParameterDescriptor. И привязываемся мы непосредственно к нему, потому что мы передаём этот объект для удаления из коллекции параметров.
CommandParameter="{Binding }"
Зная это, мы понимаем, что теперь нельзя сослаться непосредственно на команду из ViewModel, так как мы прошли в ней глубже, и теперь нам надо сделать шаг назад. Поэтому пишем так:
Command="{Binding DataContext.DeleteParameterCommand,
RelativeSource={RelativeSource Mode=FindAncestor, AncestorType={x:Type Window}}}">
То есть источник привязки мы ищем как вышестоящий относительно кнопки элемент (Ancestor), имеющий тип Window. Его DataContext — это наша ViewModel, так что так мы можем сослаться на команду из основной вьюМодели.
Тут сложно передать команду непосредственно в дескриптор. Да, мы сможем удалить параметр, но мы не сможем удалить его из коллекции параметров для View.
Заключение
В общем-то, всё. Мы получили работоспособный код (правда, в окне нет кнопки запуск, а параметр удаляется прям сразу по нажатию на кнопку, но и блог у меня не о UX/UI-дизайне плагинов). Посмотреть его и поэкспериментировать с ним можно как обычно, на GitHub.
И вновь напоминаю про свой телеграм-канал о Revit API. Заходите, подписывайтесь. До новых встреч!