Опубликован: 13.07.2010 | Уровень: специалист | Доступ: платный
Самостоятельная работа 36:

Интерфейс времени проектирования для компонента

Управление контекстным меню этапа проектирования компонента

Контекстное меню компонента появляется при щелчке на нем правой кнопкой мыши. Естественно, что пункты любого меню выполняют закрепленные за ними действия с помощью соответствующих методов. Без специальных действий над кодом компонента для него существует стандартное меню. Мы можем несколько модифицировать стандартное меню компонента режима разработки, если учтем следующее.

При добавлении ссылки на метод в смарт-тег компонента имеются 6 перегрузок библиотечного метода System.ComponentModel.Design.DesignerActionMethodItem(), три из которых своим последним параметром управляют опцией с названием displayName в контекстном меню:

  • public DesignerActionMethodItem(System.ComponentModel.Design.DesignerActionList actionList, string memberName, string displayName, bool includeAsDesignerVerb)
  • public DesignerActionMethodItem(System.ComponentModel.Design.DesignerActionList actionList, string memberName, string displayName, string category, bool includeAsDesignerVerb)
  • public DesignerActionMethodItem(System.ComponentModel.Design.DesignerActionList actionList, string memberName, string displayName, string category, string description, bool includeAsDesignerVerb)

В блоке кода №5 класса GradientLabelActionList при переопределении виртуального метода GetSortedActionItems(), унаследованного от базового класса DesignerActionList, использована перегрузка с поднятым флагом includeAsDesignerVerb, что обеспечило включение опции метода InvertColors() с названием "Перевернуть цвета" в стандартное контекстное меню компонента.


Для формирования своего контекстного меню необходимо в подключаемом к компоненту в качестве атрибута классе GradientLabelDesigner переопределить виртуальное свойство Verbs, унаследованное от класса ComponentDesigner. В свою очередь, к свойству Verbs нужно подключить экземпляр класса, содержащего коллекцию элементов контекстного меню, производного от библиотечного System.ComponentModel.Design.DesignerVerbCollection.

  • Добавьте в конец файла GradientLabelDesigner.cs блок кода №6, определяющий коллекцию элементов контекстного меню (в нашем случае это будет только один элемент, вызывающий выполнение метода VerbInvertColors() )
//*///////////////////////////////////////////////////////////////
// Блок кода №6. Формирование коллекции элементов контекстного меню компонента
//////////////////////////////////////////////////////////////////
namespace MyControl
{
    internal class GradientLabelVerbCollection : DesignerVerbCollection
    {
        // Объявили ссылку на объект компонента
        GradientLabel gradientLabel;
    
        // Конструктор
        public GradientLabelVerbCollection(IComponent component)
        {
            // Привели и сохранили ссылку на редактируемый компонент
            gradientLabel = (GradientLabel)component;
    
            // Создаем пункты меню (всего один пункт)
            this.Add(new DesignerVerb("Перевернуть &цвета_1",
                new EventHandler(VerbInvertColors)));
        }
    
        // Соблюдаем сигнатуру библиотечного делегата EventHandler 
        private void VerbInvertColors(object sender, EventArgs args)
        {
            // Извлекаем ссылки на свойства компонента 
            PropertyDescriptor start = GetPropertyByName("StartColor");
            PropertyDescriptor end = GetPropertyByName("EndColor");
    
            // Извлекаем значения свойств и меняем их местами
            Color tmp = (Color)start.GetValue(gradientLabel);
            start.SetValue(gradientLabel, end.GetValue(gradientLabel));
            end.SetValue(gradientLabel, tmp);
        }
    
        // Вспомогательная функция реализации отражения, дублирована
        private PropertyDescriptor GetPropertyByName(String propName)
        {
            PropertyDescriptor prop =
                TypeDescriptor.GetProperties(gradientLabel)[propName];
            if (prop == null)
                throw new ArgumentException("Свойство не существует", propName);
            return prop;
        }
    }
}
//***************************************************************/
Листинг 36.13. Формирование контекстного меню ручным способом
  • В конец файла GradientLabelDesigner.cs добавьте блок кода №7 переопределения наследуемого виртуального свойства Verbs для добавления опции " Перевернуть &цвета_1 " в контекстное меню компонента
//*///////////////////////////////////////////////////////////////
// Блок кода №7. Добавление коллекции контекстного меню к компоненту
//////////////////////////////////////////////////////////////////
namespace MyControl
{
    partial class GradientLabelDesigner
    {
        DesignerVerbCollection verbs; // Базовое поле
    
        // Переопределение виртуального свойства Verbs, унаследованного 
        // классом System.Windows.Forms.Design.ControlDesigner от
        // класса System.ComponentModel.Design.ComponentDesigner 
        public override DesignerVerbCollection Verbs
        {
            get
            {
                // Если еще не создавали контекстное меню компонента
                if (verbs == null)
                {
                    verbs=new GradientLabelVerbCollection(this.Component);
                }
    
                return verbs;
            }
        }
    }
}  
//***************************************************************/
Листинг 36.14. Добавление пунктов контекстного меню к компоненту GradientLabel
  • Откомпилируйте проект и убедитесь, что контекстное меню компонента на этапе проектирования работает нормально и имеет вид


Мы рассмотрели два способа создания контекстного меню. На нашем примере можно убедиться, что оба способа обладают одинаковой функциональностью. Первый способ при добавлении элементов в смарт-тег с применением параметра includeAsDesignerVerb = true проще, но второй способ может пригодиться, когда формируется контекстное меню без предварительного создания смарт-тега. Хотя при формировании только контекстного меню все равно автоматически создается смарт-тег, содержащий опции контекстного меню. Чтобы убедиться в этом, выполните следующее:

  • Закомментируйте блок №4 файла GradientLabelDesigner.cs, отвечающий за создание смарт-тега. Для этого удалите один из двух слэшей, стоящих в заголовке блока кода перед символом звездочки
/*////////////////////////////////////////////////////////////////
// Блок кода №4. Создание смарт-тега с заданным списком элементов
//////////////////////////////////////////////////////////////////
namespace MyControl
{
    partial class GradientLabelDesigner
    {
        // Базовое поле
        DesignerActionListCollection actionLists;
    
        // Переопределение виртуального свойства ActionLists, унаследованного 
        // классом System.Windows.Forms.Design.ControlDesigner от
        // класса System.ComponentModel.Design.ComponentDesigner 
        public override DesignerActionListCollection ActionLists
        {
            get
            {
                // Если еще не создавали смарт-тег actionLists
                if (actionLists == null)
                {
                    // Создали окно смарт-тега
                    actionLists = new DesignerActionListCollection();
                    // Создали список элементов окна
                    GradientLabelActionList gradientLabelActionList =
                        new GradientLabelActionList(this.Component);
                    // Добавили список элементов в коллекцию окна
                    actionLists.Add(gradientLabelActionList);
                }
    
                return actionLists;
            }
        }
    }
}
//***************************************************************/
Листинг 36.15. Файл GradientLabelDesigner.cs с отключенным кодом создания смарт-тега
  • Откомпилируйте все решение и убедитесь, что смарт-тег с опциями, добавляемыми в контекстное меню, создается автоматически


  • Раскомментируйте блок кода №4 построения смарт-тега для продолжения исследования техники построения интерфейса компонента для режима проектирования. Для этого добавьте еще один слэш перед звездочкой в начале заголовка блока кода
//*////////////////////////////////////////////////////////////////
// Блок кода №4. Создание смарт-тега с заданным списком элементов
//////////////////////////////////////////////////////////////////
namespace MyControl
{
    partial class GradientLabelDesigner
    {
        ..................................................
    }
}
//***************************************************************/
Листинг 36.16. Файл GradientLabelDesigner.cs с включенным кодом создания смарт-тега
Александр Очеретяный
Александр Очеретяный
Украина, Киев
Анастасия Балыбердина
Анастасия Балыбердина
Украина, Киев, НТУУ КПИ