- •Краткий путеводитель
- •Проектируйте
- •Сохраняйте гибкость
- •Коллекции элементов
- •Отрисовка
- •Придерживайтесь стандартов
- •Оптимизируйте
- •Взаимодействие с мышью
- •Взаимодействие с клавиатурой
- •Поведение в режиме дизайна
- •Использование атрибутов
- •Коллекции
- •Конверторы типов
- •Расширение компонентов
- •Локализация
- •Источники данных
- •Доступность
- •Конвертор типа
Сохраняйте гибкость
Помните о том, что проще, дешевле и удобнее создать и сопровождать один настраиваемый контрол, чем десяток похожих контролов, отличающихся незначительными деталями отрисовки или поведения. Однако же не увлекайтесь созданием суперуниверсальных монстров, умеющих всё. Зачастую достаточно позволить пользователю настраивать цвета, размеры и шрифты основных частей вашего контрола. Не забывайте про различные состояния, в которых может находиться контрол, например, Selected, Pushed, Focused. Предоставьте пользователю возможность задавать альтернативное отображение контрола в некоторых состояниях. Например, для контрола вроде списка имеет смысл предоставить пользователю возможность изменить цвет, которым подсвечивается текущий элемент.
Не забывайте, что могут появиться контролы, использующие ваш контрол в качестве базового. Предоставьте ограниченный доступ к потенциально полезным для производных классов методам. Предоставляйте точки расширения путём вынесения участков кода в виртуальные методы. Особенно это касается отрисовки контрола. Если отрисовка сложная, разбейте её на несколько частей так, чтобы наследники могли перегрузить нужную часть.
Предоставляйте несколько вариантов методов там, где возможен разный формат входных данных. Например, варианты (Point pt) и (int x, int y), (Rectangle rect) и (Point pt, Size size).
Предоставляйте события, информирующие клиента изменения свойств контрола. Стандартное название для события – NNNNChanged, где NNNN – имя свойства. Тип делегата должен быть EventHandler. Используя эти события, клиенты вашего класса смогут отслеживать изменения в состоянии контрола, даже если они сложно связаны. Это также позволит системе времени дизайна правильно отслеживать состояние вашего контрола. Кроме того, наличие подобных событий является необходимым условием для подключения к источнику данных в режиме read-write, иначе система Data Binding не узнает, что именно изменилось.
Создание контрола
Коллекции элементов
Если контрол должен содержать в себе некий набор элементов, создайте классы, представляющие эти элементы, а также типизированные коллекции для их хранения. Контрол должен получать уведомления об изменениях в составе и свойствах элементов, чтобы он мог изменить своё представление адекватно состоянию. Для этого создайте в контроле специальный internal-метод, вызываемый из коллекций и их элементов при изменении состояния. Можно, конечно, использовать события и делегаты, но в данном случае это не особенно оправдано из соображений производительности, а клиенты таких сообщений заранее известны. Наследуйте коллекции от CollectionBase, переопределите методы OnClear, OnInsert, OnRemove, OnSet для того, чтобы уведомлять контрол об изменениях в составе коллекций. Определите типизированные Insert, Add, Remove, IndexOf, AddRange и индексер. Если контрол достаточно сложен, подумайте о специализированных методах, которые принимают во внимание произведенное изменение, а не используют универсальный метод вроде SomethingChangedUpdateAll.
Отслеживайте экземпляр контрола, в котором в данный момент содержится элемент. Во-первых, это необходимо для оповещения контрола об изменении свойств элемента. Во-вторых, это позволяет не допустить использования одного элемента в разных контролах одновременно и тем самым, возможно, нарушить согласованность данных.
Довольно часто требуется произвести некоторые вычисления извне контрола или воздействовать на контрол из кода. Предоставьте полезные методы для таких случаев, например, такие:
|
public ItemType GetItemAt(Point pt); public ItemType GetItemAt(int x, int y); public Rectangle GetItemRect(ItemType item); public void EnsureVisible(ItemType item);
|
Предоставляйте отдельный виртуальный защищенный метод для отрисовки элемента. В качестве параметров, кроме собственно элемента, используйте Graphics и Rectangle. Рассмотрите необходимость ограничить область рисования путём установки Graphics.Clip. Обратите внимание на отрисовку частично видимых элементов.
|
protected virtual void DrawItem(Graphics g, ItemType item, Rectangle rect);
|
