Библиотека элементов управления Ajax Control Toolkit содержит некоторые расширенные элементы управления. Используя эти расширенные элементы управления, вы можете легко добавлять эффекты Ajax к обычным элементам управления. Например, вы можете использовать элемент управления AutoCompleteExtender для добавления эффектов Ajax автоматического завершения в текстовые поля. Конечно, в данной статье речь пойдет не об этом.
Добавьте набор инструментов управления Ajax в набор инструментов Visual Studio 2008, откройте новый файл aspx и перетащите в него текстовое поле. В это время произошло нечто интересное. На панели SmartTasks TextBox действительно появилась ссылка «Добавить расширение...»! Я снова попробовал перетащить кнопку и панель, и без исключения в нижней части панели SmartTasks каждого элемента управления появилась ссылка «Добавить расширение...».
Недавно я планирую абстрагировать такие функции, как сохранение, удаление и закрытие страниц, в действиях. Каждое действие соответствует пользовательскому веб-элементу управления. После присоединения элемента управления действием к целевому элементу управления (например, кнопке) целевой элемент управления будет иметь функции. например сохранение, удаление и закрытие страниц. Как легко прикрепить действия к элементу управления «Кнопка» в дизайнере веб-форм? Мне нужно что-то вроде «Добавить расширение...».
Друзья, которые разработали собственные серверные элементы управления, должны знать, что если вы хотите добавить SmartTasks в элемент управления, вам необходимо переопределить свойство ActionLists ControlDesigner и реализовать свой собственный DesignerActionList. Очевидно, что TextBox не знает о существовании AjaxControlToolkit, поэтому «Добавить расширение...» такой DesignerActionMethodItem им не добавляется. Итак, предоставляет ли платформа .net какой-то интерфейс, который позволяет нам «динамически внедрять» DesignerActionItem в другие элементы управления?
Изучив AjaxControlToolKit.dll, я обнаружил, что разработчик этих расширенных элементов управления не несет ответственности за предоставление действия «Добавить расширение». Они отвечают только за предоставление содержимого расширения, соответствующего соответствующему расширению, поэтому единственная запись — из файла. веб-дизайнер студии Visual. Приходите учиться. Используйте отражатель, чтобы открыть Microsoft Visual Studio 9.0Common7IDEMicrosoft.Web.Design.Client.dll и найти интерфейс IWebSmartTasksProvider. Этот интерфейс имеет метод GetDesignerActionLists. Возвращаемым значением этого метода должно быть содержимое, отображаемое на панели SmartTasks. . Этот интерфейс имеет три класса реализации: DataFormDesigner, DataFormXslValueOfDesigner и ElementDesigner. Из названий этих трех классов можно сделать вывод, что ElementDesigner должен быть наиболее часто используемым классом реализации. Метод GetDesignerActionLists ElementDesigner реализован следующим образом:
1: DesignerActionListCollection IWebSmartTasksProvider.GetDesignerActionLists()
2: {
3: DesignerActionListCollection компонент Actions = null;
4: если (this.Designer != null)
5: {
6: Служба DesignerActionService = (DesignerActionService) base.DesignerHost.GetService(typeof(DesignerActionService));
7: если (сервис!= ноль)
8: {
9:ComponentActions = service.GetComponentActions(this.Designer.Component);
10: }
11: }
12: если (компонентActions == null)
13: {
14:ComponentActions = новый DesignerActionListCollection();
15: }
16: вернуть компонентActions;
17: }
18:
19:
20:
двадцать один:
Из приведенного выше кода видно, что окончательная коллекция DesignerActionListCollection определяется GetComponentActions класса System.ComponentModel.Design.DesignerActionService в сборке System.Design и Microsoft.Web.Design.WebFormDesigner в Microsoft.Web.Design.Client. dll +WebDesignerActionService наследует этот класс, и его реализация выглядит следующим образом:
1: защищенное переопределение void GetComponentDesignerActions (компонент IComponent, DesignerActionListCollection actionLists)
2: {
3: Контроль управления = компонент как элемент управления;
4: Родитель ElementDesigner = null;
5: если (управление!= ноль)
6: {
7: родитель = ElementDesigner.GetElementDesigner(управление);
8: }
9: if ((parent == null) || !parent.InTemplateMode)
10: {
11: base.GetComponentDesignerActions(компонент, actionLists);
12: if ((parent != null) && (parent.Designer != null))
13: {
14: Конструктор ControlDesigner = родительский.Designer как ControlDesigner;
15: if ((designer != null) && (designer.AutoFormats.Count > 0))
16: {
17: actionLists.Insert(0, новый AutoFormatActionList(родительский));
18: }
19: }
20: if ((parent != null) && (parent.Element != null))
двадцать один: {
22: IWebDataFormElementCallback dataFormElementCallback = родительский.Элемент.GetDataFormElementCallback();
23: если (dataFormElementCallback! = ноль)
двадцать четыре: {
25: Список DataFormElementActionList = новый DataFormElementActionList(родительский, родительский.Control, dataFormElementCallback);
26: actionLists.Add(список);
27: DataFormElementActionList.ModifyActionListsForListControl(actionLists, list);
28: }
29: }
30: if (((родительский != null) && (parent.Designer != null)) && родительский.DocumentDesigner.ExtenderControlHelper.ProvidesActionLists)
31: {
32: родительский.DocumentDesigner.ExtenderControlHelper.AddActionLists(родительский, actionLists);
33: }
34: }
35: if ((parent != null) && (parent.TemplateEditingUI != null))
36: {
37: actionLists.Add(новый TemplateEditingActionList(parent.TemplateEditingUI, родительский.Элемент));
38: }
39: }
40:
41:
42:
43:
В этом методе есть такой абзац:
1: if (((родительский != null) && (parent.Designer != null)) && родительский.DocumentDesigner.ExtenderControlHelper.ProvidesActionLists)
2: {
3: родительский.DocumentDesigner.ExtenderControlHelper.AddActionLists(родительский, actionLists);
4: }
Кажется, сюда добавлено действие "Добавить расширение". Продолжайте рассматривать реализацию ExtenderControlHelper.AddActionLists:
1: public void AddActionLists (элемент ElementDesigner, списки DesignerActionListCollection)
2: {
3: lists.Add(new ControlExtenderActionList(element));
4: Компонент ExtenderControl = element.Designer.Component как ExtenderControl;
5: Элемент управления = элемент.Designer.Component как элемент управления;
6: if ((компонент == null) && (control != null))
7: {
8: служба IExtenderInformationService = (IExtenderInformationService) control.Site.GetService(typeof(IExtenderInformationService));
9: если (сервис!= ноль)
10: {
11: foreach (Управление control3 в service.GetAppliedExtenders(control))
12: {
13: lists.Add(new HoistedExtenderActionList(element.Designer, control3));
14: }
15: }
16: }
17: }
18:
19:
20:
двадцать один:
Первое предложение в этом методе — lists.Add(new ControlExtenderActionList(element)). ControlExtenderActionList наследует System.ComponentModel.Design.DesignerActionList. Его метод GetSortedActionItems определяется следующим образом:
1: общедоступное переопределение DesignerActionItemCollection GetSortedActionItems()
2: {
3: Компонент управления = (Control) this._htmlDesigner.Component;
4: элементы DesignerActionItemCollection = новый DesignerActionItemCollection();
5: служба IExtenderInformationService = (IExtenderInformationService) компонент.Site.GetService(typeof(IExtenderInformationService));
6: категория строки = SR.GetString(SR.Ids.SmartTasksLabelExtenderSection, CultureInfo.CurrentUICulture);
7: если (service.IsControlExtendible(компонент))
8: {
9: строка displayName = SR.GetString(SR.Ids.SmartTasksAddExtender, CultureInfo.CurrentUICulture);
10: items.Add(new DesignerActionMethodItem(this, «AddExtender», displayName, Category, true));
11: }
12: если (service.IsControlExtended(компонент))
13: {
14: строка str3 = SR.GetString(SR.Ids.SmartTasksRemoveExtender, CultureInfo.CurrentUICulture);
15: items.Add(new DesignerActionMethodItem(this, «RemoveExtender», str3, Category, true));
16: }
17: возврат предметов;
18: }
19:
Теперь понятно, что действие «Добавить расширение» жестко запрограммировано в дизайнере веб-форм Visual Studio. Платформа .net не предоставляет нам соответствующего интерфейса для добавления подобных действий. Но мне нужен эффект «добавить действие», поэтому я не могу обратиться к методу AjaxControlToolkit для его достижения, мне следует искать другие методы.
Вернитесь назад и еще раз изучите метод GetComponentActions класса Microsoft.Web.Design.WebFormDesigner+WebDesignerActionService и найдите определение базового класса System.Web.UI.Design.WebFormsDesignerActionService (в сборке System.Design), как показано ниже:
1: защищенное переопределение void GetComponentDesignerActions (компонент IComponent, DesignerActionListCollection actionLists)
2: {
3: если (компонент == ноль)
4: {
5: создать новое исключение ArgumentNullException («компонент»);
6: }
7: если (списки действий == ноль)
8: {
9: создать новое исключение ArgumentNullException("actionLists");
10: }
11: сайт IServiceContainer = компонент. Сайт как IServiceContainer;
12: если (сайт != ноль)
13: {
14: Служба DesignerCommandSet = (DesignerCommandSet) site.GetService(typeof(DesignerCommandSet));
15: если (сервис!= ноль)
16: {
17: списки DesignerActionListCollection = service.ActionLists;
18: if (списки != ноль)
19: {
20: actionLists.AddRange(списки);
двадцать один: }
двадцать два: }
23: if ((actionLists.Count == 0) || ((actionLists.Count == 1) && (actionLists[0] — это ControlDesigner.ControlDesignerActionList)))
двадцать четыре: {
25: глаголы DesignerVerbCollection = service.Verbs;
26: if ((verbs != null) && (verbs.Count != 0))
27: {
28: массив DesignerVerb[] = новый DesignerVerb[verbs.Count];
29: глаголы.CopyTo(массив, 0);
30: actionLists.Add(новый DesignerActionVerbList(массив));
31: }
32: }
33: }
34: }
35:
36:
37:
38:
Изучая приведенный выше код, мы видим, что DesignerActionListCollection возвращается атрибутом ActionLists службы DesignerCommandSet, и эта служба получается с сайта компонента, пока я пишу еще один DesignerCommandSet и гарантирую, что DesignerCommandSet извлечен из. Сайт мой. Просто напишите этот сервис. Наконец нашел точку входа, вот конкретный метод.
Сначала создайте класс, наследующий DesignerCommandSet, следующим образом:
1: общедоступный класс MyDesignerCommandSet: DesignerCommandSet
2: {
3: частный ComponentDesigner _comComponentDesigner;
4:
5: общедоступный MyDesignerCommandSet (ComponentDesignerComponentDesigner)
6: {
7: _comComponentDesigner = компонентDesigner;
8: }
9:
10: общедоступное переопределение ICollection GetCommands (имя строки)
11: {
12: if (name.Equals("ActionLists"))
13: {
14: вернуть GetActionLists();
15: }
16: вернуть base.GetCommands(имя);
17: }
18:
19: частная коллекция DesignerActionListCollection GetActionLists()
20: {
21: //Сначала получаем исходные списки DesignerActionLists элемента управления
22: списки DesignerActionListCollection = _comComponentDesigner.ActionLists;
двадцать три:
24: //Добавляем DesignerActionList «Добавить действие»
25: lists.Add(new ActionList(_comComponentDesigner));
26: списки возврата;
27: }
28:
29: внутренний класс ActionList: DesignerActionList
30: {
31: частные DesignerActionItemCollection _actions;
32:
33: общедоступный ActionList (конструктор IDesigner)
34: : база(дизайнер.Компонент)
35: {
36: }
37: общедоступное переопределение DesignerActionItemCollection GetSortedActionItems()
38: {
39: если (_actions == null)
40: {
41: константная строка actionCategory = «Действия»;
42: _actions = новый DesignerActionItemCollection();
43: _actions.Add(new DesignerActionMethodItem(this, "AddAction", "Добавить действие...", actionCategory, true));
44: }
45: вернуть _actions;
46: }
47:
48: общественная недействительность AddAction()
49: {
50: //Добавить логику действия, опущено
51: }
52: }
53: }
Следующий шаг — заставить Site ServiceProvider компонента возвращать собственную службу. Метод заключается в том, чтобы написать сайт самостоятельно и сделать сайт компонента объектом написанного вами класса SIte.
Определение класса Site, которое я написал, выглядит следующим образом:
1: общедоступный класс SiteProxy: ISite, IServiceContainer
2: {
3: частный ISite_site;
4: частный ComponentDesigner _designer;
5:
6: публичный SiteProxy (сайт ISite, дизайнер ComponentDesigner)
7: {
8: _сайт = сайт;
9: _designer = дизайнер;
10:
11: }
12:
13: #region участники ISite
14:
15: общедоступный компонент IComponentComponent
16: {
17: получить {возврат _site.Component};
18: }
19:
20: общедоступный контейнер System.ComponentModel.IContainer
двадцать один: {
22: получить {вернуть _site.Container};
двадцать три: }
двадцать четыре:
25: общедоступный boolDesignMode
26: {
27: получить {вернуться _site.DesignMode};
28: }
29:
30: имя публичной строки
31: {
32: получить {возврат _site.Name};
33: установить {_site.Name = значение};
34: }
35:
36: #конецрегиона
37:
38: член #region IServiceProvider
39:
40: общедоступный объект GetService (Тип serviceType)
41: {
42: служба объекта = _site.GetService(serviceType);
43:
44: if (serviceType == typeof(DesignerCommandSet) && !(_designer.Component is ExtenderControl))
45: {
46: if (service == null || !(сервис MyDesignerCommandSet))
47: {
48: если (сервис!= ноль)
49: {
50: RemoveService(typeof(DesignerCommandSet));
51: }
52: //Вернем DesignerCommandSet, написанный вами
53: сервис = новый MyDesignerCommandSet(_designer);
54: AddService(typeof(DesignerCommandSet), сервис);
55: }
56: }
57: услуга возврата;
58: }
59:
60: #конецрегиона
61:
62: член #region IServiceContainer
63:
64: public void AddService (Type serviceType, обратный вызов ServiceCreatorCallback, продвижение bool)
65: {
66: (_site as IServiceContainer).AddService(serviceType, обратный вызов, продвижение);
67: }
68:
69: public void AddService (Тип serviceType, обратный вызов ServiceCreatorCallback)
70: {
71: (_site as IServiceContainer).AddService(serviceType, обратный вызов);
72: }
73:
74: public void AddService (Тип serviceType, объект serviceInstance, bool продвижение)
75: {
76: (_site as IServiceContainer).AddService(serviceType, serviceInstance, продвигать);
77: }
78:
79: public void AddService (Тип serviceType, объект serviceInstance)
80: {
81: (_site as IServiceContainer).AddService(serviceType, serviceInstance);
82: }
83:
84: public void RemoveService (Тип serviceType, bool продвижение)
85: {
86: (_site as IServiceContainer).RemoveService(serviceType, продвигать);
87: }
88:
89: public void RemoveService (Тип serviceType)
90: {
91: (_site как IServiceContainer).RemoveService(serviceType);
92: }
93:
94: #конецрегиона
95: }
В методе GetService этого сайта определите тип службы, которую необходимо получить. Если это DesignerCommandSet, верните созданный вами MyDesignerCommandSet.
Следующий шаг — изменить Site компонента на SiteProxy, написанный вами. Один из способов — добавить пользовательский элемент управления и изменить сайт других элементов управления в контейнере в методе Initialize ControlDesigner элемента управления. Вам нужно только перетащить элемент управления в веб-форму, чтобы изменить сайт других элементов управления. Метод заключается в написании пакета vs и захвате соответствующих событий дизайнера веб-форм в пакете. Первый подход представлен ниже:
Добавьте новый элемент управления, унаследованный от Control, под названием ActionManager. Для этого элемента управления не требуется добавлять какие-либо функции. Вам нужно только создать для него ControlDesigner. Основной код класса ControlDesigner выглядит следующим образом:
1: общедоступный класс ActionManagerDesigner: ControlDesigner
2: {
3: частный IDesignerHost _host;
4: частный IDictionary<IComponent, ISite> _comComponents;
5:
6: общедоступное переопределение void Initialize (компонент IComponent)
7: {
8: base.Initialize(компонент);
9:
10: _comComponents = новый словарь<IComponent, ISite>();
11:
12: _host = GetService(typeof(IDesignerHost)) как IDesignerHost;
13: если (_host!= ноль)
14: {
15: //Заменяем сайт существующими элементами управления
16: ПроцессКомпонент();
17:
18: служба IComponentChangeService =
19: _host.GetService(typeof(IComponentChangeService)) как IComponentChangeService;
20: если (сервис!= ноль)
двадцать один: {
22: service.ComponentAdded += ComponentAdded;
23: service.ComponentRemoving += ComponentRemoving;
двадцать четыре: }
25: }
26: }
27:
28: #regionProcessComponent
29:
30: частный void ProcessComponent()
31: {
32: Компоненты ComponentCollection = _host.Container.Components;
33: foreach (компонент IComponent в компонентах)
34: {
35: if (компонент ActionControl)
36: продолжить;
37: ProcessComponentSite(компонент);
38: }
39: }
40:
41: #конецрегиона
42:
43: #region заменить сайт
44:
45: /// <резюме>
46: /// Замените исходный сайт компонента на SiteProxy
47: /// </summary>
48: частная пустота ProcessComponentSite (компонент IComponent)
49: {
50: конструктор ComponentDesigner = _host.GetDesigner(компонент) как ComponentDesigner;
51: _comComponents[компонент] = компонент.Сайт;
52: компонент.Сайт = новый SiteProxy(компонент.Сайт, дизайнер);
53: }
54:
55: /// <сводка>
56: /// Восстанавливаем исходный сайт Компонента
57: /// </summary>
58: /// <param name="comComponent"></param>
59: частная пустота RestoreComponentSite (компонент IComponent)
60: {
61: если (_comComponents.ContainsKey(компонент))
62: {
63: сайт ISite = _comComponents[компонент];
64: компонент.Сайт = сайт;
65: _comComponents.Remove(компонент);
66: }
67: }
68:
69: #конецрегиона
70:
71: #region для компонента Добавить, удалить, изменить
72:
73: частный void ComponentRemoving (отправитель объекта, ComponentEventArgs e)
74: {
75: если (e.Component — это ActionControl)
76: {
77: возвращение;
78: }
79: //При удалении компонента его свойство Site должно быть восстановлено, иначе исходный сайт останется в DesignerHost.
80: //При добавлении компонента с таким же именем таким образом будет сообщено об ошибке «дубликат имени компонента».
81: RestoreComponentSite(e.Component);
82: }
83:
84:
85: частный void ComponentAdded (отправитель объекта, ComponentEventArgs e)
86: {
87: if (e.Component — это ActionControl)
88: {
89: возвращение;
90: }
91: ProcessComponentSite(e.Component);
92: }
93:
94: #конецрегиона
95:
96: #region располагать
97:
98: защищенное переопределение void Dispose (удаление bool)
99: {
100: если (_host!= ноль)
101: {
102: служба IComponentChangeService =
103: _host.GetService(typeof(IComponentChangeService)) как IComponentChangeService;
104: если (сервис!= ноль)
105: {
106: service.ComponentAdded -= ComponentAdded;
107: service.ComponentRemoving -= ComponentRemoving;
108: }
109: }
110: base.Dispose(удаление);
111: }
112:
113: #конецрегиона
114: }
На этом этапе, перетаскивая элемент управления ActionManager в конструктор веб-форм, вы можете видеть ссылку «Добавить действие...» на панели интеллектуальных задач других элементов управления. Однако этот метод требует размещения дополнительного элемента управления в конструкторе веб-форм. Этот элемент управления полезен только во время разработки и бесполезен во время выполнения. Это выглядит странно, поэтому лучшим подходом является второй подход, который заключается в разработке пакета vs. в методе Initialize пакета зарегистрируйте событие DesignerCreated IDesignerEventService, а затем добейтесь цели изменения сайта управления через IDesignerHost и IComponentChangeService. Конкретная реализация аналогична приведенной выше, поэтому я больше не буду ее писать.