Программирование >>  Привязка данных 

1 ... 6 7 8 [ 9 ] 10


□ член должен быть методом;

□ член должен быть общедоступным методом экземпляра (не статическим);

□ член должен возвращать void;

□ член должен принимать ноль параметров;

□ член должен включать ContextMenuAttribute.

Последний из этих критериев ссылается на заказной атрибут, написанный специально для данного примера (мы говорили о нем после обсуждения метода PopupMenu).

ContextMenu menu = new ContextMenu(); foreach (MethodInfo meth in members)


Рис. 32.25. Результирующее контекстное меню

... Добавить элемент меню

System.Drawing.Point pt = new System.Drawing.Point(x,y); menu.Show(parent, pt);

Экземпляр контекстного меню создан с элементами, добавленными для каждого из методов, отвечающих указанным критериям. Затем это меню отображается, как показано на рис. 32.25.

Главная сложность этого примера заключена в следующем фрагменте кода, повторенном по одному разу для каждой функции-члена, которая должна быть отображена во всплывающем меню:

System.Type ctxtype =

typeof(ContextMenuAttribute); ContextMenuAttribute[]

ctx = (ContextMenuAttribute[])

meth.GetCustomAttributes(ctxtype, true); MenuCommand callback = new MenuCommand(this, meth);

MenuItem item = new MenuItem(ctx[0].Caption, new EventHandler(callback.Execute));

item.DefaultItem = ctx[0].Default;

menu.MenuItems.Add(item);

Каждый метод, который должен быть отображен в контекстном меню, снабжен атрибутом ContextMenuAttribute. Он определяет дружественное к пользователю имя команды меню, поскольку имена методов C# не могут включать пробелов, к тому же во всплывающем меню разумно использовать естественный язык вместо имен внутреннего кода. Атрибут извлекается из метода, и новый элемент меню создается и добавляется к коллекции команд всплывающего меню.

Пример кода также демонстрирует применение упрощенного класса Command (общий проектный шаблон). Класс MenuCommand, используемый в данном экземпляре, инициируется пользователем при выборе элемента контекстного меню и передает вызов приемнику метода - в данном случае, объекту и его методу, снабженному атрибутом. Это также позволяет изолировать код объекта-приемника от кода пользовательского интерфейса. Код объясняется в последующих разделах.

Таблицы и записи, созданные вручную

Ранее приведенный в этой главе пример XSD показывал код набора классов доступа к данным, созданный путем генерации средствами редактора Visual Studio .NET. Следующий класс показывает необходимые методы DataTable, которые предельно минимизированы (и написаны вручную).



public class CustomerTable : DataTable

public CustomerTable() : base( Customers )

this.Columns.Add( CustomerID , typeof(string)); this.Columns.Add( CompanyName , typeof(string)); this.Columns.Add( ContactName , typeof(string));

protected override System.Type GetRowType()

return typeof(CustomerRow); protected override DataRow NewRowFromBuilder(DataRowBuilder builder)

return(DataRow) new CustomerRow(builder);

Первое требование - DataTable должен переопределить метод GetRowType(). Он используется внутри .NET при генерации новых записей таблицы. Этого достаточно для минимальной реализации. Соответствующий класс CustomerRow достаточно прост. Он реализует свойства для каждой из столбцов записи и затем реализует методы, которые в конечном итоге отображаются в контекстном меню:

public class CustomerRow : ContextDataRow

public CustomerRow(DataRowBuilder builder) : base(builder)

public string CustomerID

get { return (string)this[ CustomerID ];} set { this[ CustomerID ] = value;}

Прочие свойства опущены для ясности [ContextMenu( Blacklist Customer )] public void Blacklist()

Делать что-то

[ContextMenu( Get Contact ,Default=true)] public void GetContact()

Делать что-то еще

Класс просто наследуется от ContextDataRow, включая соответствующие методы get/set для свойств, чьи имена совпадают с именами полей, а затем добавляет методы, которые применяются средствами рефлексии при построении контекстного меню:

[ContextMenu( Blacklist Customer )]

public void Blacklist()

Делать что-то

Каждый отображаемый в контекстном меню метод имеет одну и ту же сигнатуру и включает заказной атрибут ContextMenu.



Использование атрибута

Идея написания атрибута ContextMenu заключается в том, чтобы можно было применять произвольное текстовое имя для данной команды меню. Следующий пример также добавляет флаг Default, используемый для пометки команды меню по умолчанию. Полный класс атрибута представлен ниже.

[AttributeUsage(AttributeTargets.Method,AllowMultiple=false,Inherited=true)] public class ContextMenuAttribute : System.Attribute

public ContextMenuAttribute(string caption)

Caption = caption; Default = false;

public readonly string Caption;

Атрибут AttributeUsage класса помечает ContextMenuAttribute как единственный используемый атрибут метода, а также указывает, что для каждого данного метода может существовать только один экземпляр этого атрибута. Конструкция Inherited=true говорит о том, что атрибут может быть помещен в метод суперкласса и наследоваться его подклассами.

К этому атрибуту можно добавить ряд других членов, включая следующие:

□ горячая клавиша выбора меню;

□ отображаемый графический образ;

□ некоторый текст, который может быть показан в строке состояния при наведении указателя мыши на команду меню;

□ идентификатор контекст подсказки.

Диспетчеризация методов

Когда меню отображается в .NET, каждая его команда привязана к обрабатывающему коду с помощью делегата. Существуют два варианта реализации механизма подключения кода к командам меню.

□ Реализовать метод с такой же сигнатурой, как у System.EventHandler. Это определено в следующем фрагменте:

public delegate void EventHandler(object sender, EventArgs e);

□ Определить прокси-класс, реализующий предыдущий делегат, и перенаправить вызов классу-приемнику. Это известно, как шаблон Command, и именно такой вариант был использован в рассмотренном примере.

Шаблон Command (Команда) разделяет отправителя и приемника вызова посредством простого класса-посредника. Он может показаться избыточным для данного примера, но это упрощает методы каждого DataRow (поскольку им не нужно передавать делегату параметры) и обеспечивает возможность расширения:

public class MenuCommand

public MenuCommand(object receiver, MethodInfo method)

Receiver = receiver; Method = method;



1 ... 6 7 8 [ 9 ] 10

© 2006 - 2024 pmbk.ru. Генерация страницы: 0
При копировании материалов приветствуются ссылки.
Яндекс.Метрика