PropertyGrid FAQ

Содержимое

От "копипастера"

Это репост оригинальной статьи размещённой здесь под авторством Алексея Кирюшкина. С момента опубликования стать прошло уже почти 15 лет и с того времени произошли некоторые изменения. Эта перепечатка материала попытка освежить код оригинальной статьи и сделать копию для себя любимого сообщества. Также я попробую добавить некоторые дополнительные детали, методы и приёмы использования.

Вступление

PropertyGrid – удобный компонент для визуального редактирования свойств объектов, либо по документации предоставляет интерфейс пользователя, который используется как обозреватель для свойств объекта. Объект для редактирования можно задать в дизайнере WinForms, либо непосредственно в коде:

Хотя PropertyGrid умеет редактировать многие стандартные типы изначально (см. ниже), чаще всего на практике требуется адаптировать элемент под собственные нужды. Также стоит упомянуть, что для своей работы PropertyGrid активно использует аннотации данных (аттрибуты) имена типов которых далее в тексте упоминаются без суффикса "Attribute" для экономии места и лучшего восприятия.

Редактирование свойства типа DateTime

Как изменить отображаемое имя свойства и его описание?

В приведённом выше примере можно заметить, что по-умолчанию в PropertyGrid для отображаемого имени свойства используется его имя, а также пусто описание свойства. Так происходит потому что мы не декорировали свойство необходимыми атрибутами. Для изменения отображаемого имени свойства предназначен атрибут DisplayName, а его описания Description:

Отображение свойства декорированного атрибутами DisplayName и Description

Как сгруппировать свойства по категориям?

Можно заметить, что свойства объекта помещаются в категорию Misc, если не указано другое. Указать же PropertyGrid категорию свойства можно атрибутом Category:

Группировка свойств по атрибуту Category

Как сделать свойство недоступным для редактирования?

Можно в автосвойстве оставить только метод get, либо декорировать его атрибутом ReadOnly:

Свойства доступные только для чтения

Как заменить стандартные значения true/false в отображении свойств типа bool?

Для замены стандартных значений true/false при редактировании булевых свойств необходимо создать свой конвертер, унаследовав его от класса TypeConverter и пометить свойство одноименным атрибутом TypeConverter.

Стандартные значения при редактировании bool свойства
Переопределённые значения bool свойства
Дополнение от "копипастера"

Вышеприведённый пример хоть и является работоспособным, но всё таки обладает одним недостатком, а именно дублированием кода при необходимости иметь для разных булевых свойств, разные текстовые соответствия, напр. "Включено/Выключено", "Активен/Не активен", "Да/Нет" и т.д.. Поэтому я предлагаю добавить атрибут, который будет содержать текстовые значения для необходимого свойства, а конвертер будет их использовать. Для начала создаём атрибут (проверки опущены для экономии места):

Различные значения с одним и тем-же конвертером

Как заменить стандартное отображение имен членов перечисления?

Для этого декорируем атрибутом Description каждый член перечисления и реализуем свой конвертер наследовав его от EnumConverter:

Использование EnumTypeConverter

Как показать иконку для каждого значения из перечисления?

Необходимо реализовать своего наследника UITypeEditor и в нём переопределить отрисовку:

Использование иконок для перечисления

Как организовать выбор значения из выпадающего списка, формируемого программно?

Необходимо реализовать TypeConverter, предоставляющий список, из которого можно будет делать выбор:

В данном случае возвращается список строк из настроек программы. Затем нужно задать этот класс в качестве параметра атрибута TypeConverter для редактируемого свойства:

Значения выпадающего списка формируемого программно

Аналогично реализуется и выбор из списка фиксированных значений например double - см. класс PossibleValuesTypeConverter в тестовом проекте.

Как избавиться от ошибки "Конструктор для типа "System.String" не найден" при редактировании свойств типа StringCollection?

... открываются для редактирования в PropertyGrid, но при попытке добавить строку к списку выдается сообщение об ошибке "Конструктор для типа "System.String" не найден" (Constructor on type "System.String" not found):

Ошибка при редактировании свойства типа StringCollection

Исправить положение можно добавив атрибут Editor со следующими параметрами:

Окно редактирования StringCollection примет при этом следующий вид:

Корректное редактирование свойства типа StringCollection

Как реализовать отображение составного свойства?

Бывает так, что тип свойства является сложным объектом, также имеющим свойства и конечно хотелось бы иметь возможность редактировать свойства этого объекта в раскрывающемся списке. Для этого к классу, используемому в качестве типа составного свойства, необходимо применить атрибут TypeConverter с ExpandableObjectConverter в качестве параметра:

Задавать дополнительные атрибуты для редактируемого свойства не нужно:

Редактирование составного свойства

Как организовать выбор файла с заданным расширением?

Для этого необходимо реализовать свой Editor наследуемый от FileNameEditor

После этого можно декорировать свойство:

Выбор файла с заданным расширением

Как организовать редактирование свойства в собственной форме?

Необходимо реализовать наследника UITypeEditor, обеспечивающего вызов нужной формы (в данном случае IPAddressEditorForm), передачу ей редактируемого значения и получение результата:

Затем, как обычно, декорируем свойство:

Редактирование свойства в собственной форме

Как организовать редактирование свойства в выпадающем списке?

Опять же, реализовать своего наследника UITypeEditor, отображающего выпадающий список с нужным control-ом, передать ему исходное значение редактируемого свойства и принять результат по окончании редактирования (ForeignLangsControl – составной UserControl c элементами, необходимыми для редактирования свойства):

Далее декорируем свойство:

Редактирование свойства в выпадающем списке

Как скрыть пароль при редактировании?

Для этого необходимо декорировать свойство атрибутом PasswordPropertyText:

Скрытие пароля при редактировании свойства в PropertyGrid

Как управлять видимостью свойства в зависимости от значения другого свойства?

Стандартный атрибут Browsable позволяет задавать видимость свойства в PropertyGrid только на этапе написания кода. Чтобы управлять видимостью свойства в зависимости от значения другого свойства настраиваемого объекта, понадобится новый атрибут - DynamicPropertyFilter и базовый класс – FilterablePropertyBase:

Указываем базовый класс для класса настраиваемого объекта:

А для свойства, видимость которого зависит от другого свойства – атрибут DynamicPropertyFilter:

Также нужно добавить обработчик события PropertyGrid.PropertyValueChanged:

В данном случае свойство PersonalFileName (Имя файла личного дела) будет показано в PropertyGrid только тогда, когда свойство EmployeePosition (Должность) будет иметь любое из указанных в атрибуте значений:

Отображение свойства в PropertyGrid в зависимости от другого свойства

Если переключить свойство Должность в значение, отсутствующее в параметре атрибута DynamicPropertyFilter, свойство Личное дело исчезнет из списка отображаемых свойств:

Скрытие свойства в PropertyGrid в зависимости от другого свойства

Аналогично, вторым параметром атрибута DynamicPropertyFilter можно передавать значения параметров других типов, например, перечисления или bool:

Решение не красивое, так как делает данные зависимыми от средств отображения и редактирования.

Как избавиться от стандартного "(Collection)" в правой колонке для свойств-коллекций?

Для этого необходимо реализовать CollectionTypeConverter:

И далее использовать CollectionTypeConverter как параметр в атрибуте TypeConverter:

Замена стандартного отображения Collection

При переходе к редактированию коллекции отобразится стандартное окно CollectionEditor с данными редактируемой коллекции:

Редактирование коллекции

Как заменить стандартные подписи (Members, properties) в окне Collection Editor?

"Members", "properties", "Add" и "Remove" можно заменить русскими аналогами переключением CurrentUICulture,как это сделано в методе Main() тестовой программы:

Однако, если надпись "Члены" над списком телефонов вас тоже не устраивает, можно применить и более радикальный способ. Заодно решим и следующую проблему.

Как добавить в Collection Editor окно с расширенной подсказкой по редактируемым свойствам?

Реализуем потомка CollectionEditor - PhoneNumbersCollectionEditor, который умеет запоминать положение и размеры своего окна, меняет стандартные подписи на соответствующие редактируемым данным и добавляет окно с расширенной подсказкой по свойствам:

Далее добавляем к свойству-коллекции атрибут Editor со специализированной версией CollectionEditor:

Использование PhoneNumbersCollectionEditor

Как задать отличный от алфавитного порядок следования свойств внутри категории?

Нужно реализовать новый атрибут для задания порядка сортировки – PropertyOrderAttribute, и наследника ExpandableObjectConverter (PropertySorter), возвращающего список свойств, упорядоченный согласно значениям, заданным для них в атрибуте PropertyOrder:

Задаем атрибут TypeConverter с параметром PropertySorter для всего класса с настраиваемыми свойствами и указываем атрибут PropertyOrder для упорядочиваемых свойств:

Переопределение порядка сортировки свойств

Как запомнить и восстановить положение разделителя колонок в PropertyGrid?

Это можно сделать следующим образом:

Вызываются методы перед загрузкой и закрытием окна формы, содержащей PropertyGrid:

Комментарии

Популярные сообщения из этого блога