تحتوي مكتبة التحكم Ajax Control Toolkit على بعض عناصر التحكم الموسعة. باستخدام عناصر التحكم الموسعة هذه، يمكنك بسهولة إضافة تأثيرات Ajax إلى عناصر التحكم العادية. على سبيل المثال، يمكنك استخدام عنصر التحكم AutoCompleteExtender لإضافة تأثيرات ajax للإكمال التلقائي إلى مربعات النص. وبطبيعة الحال، ليس هذا ما يريد هذا المقال مناقشته.
أضف مجموعة أدوات التحكم Ajax إلى صندوق أدوات Visual Studio 2008، وافتح ملف aspx جديدًا، واسحب مربع نص إليه. في هذا الوقت، حدث شيء مثير للاهتمام في لوحة SmartTasks في TextBox، ظهر بالفعل رابط "إضافة ملحق..."! حاولت سحب الزر واللوحة مرة أخرى، وبدون استثناء، ظهر رابط "إضافة ملحق..." أسفل لوحة SmartTasks لكل عنصر تحكم.
في الآونة الأخيرة، أخطط لتجريد الوظائف مثل حفظ الصفحات وحذفها وإغلاقها إلى إجراءات. يتوافق كل إجراء مع عنصر تحكم ويب مخصص. بعد إرفاق عنصر تحكم الإجراء بعنصر التحكم الهدف (مثل الزر)، سيكون لعنصر التحكم الهدف وظائف مثل حفظ الصفحات وحذفها وإغلاقها. كيفية إرفاق الإجراءات بسهولة بعنصر تحكم الزر في مصمم WebForm؟ ما أريده هو شيء مثل "إضافة ملحق...".
يجب أن يعرف الأصدقاء الذين قاموا بتطوير عناصر تحكم مخصصة للخادم أنه إذا كنت تريد إضافة SmartTasks إلى عنصر التحكم، فأنت بحاجة إلى تجاوز خاصية ActionLists الخاصة بـ ControlDesigner وتنفيذ DesignerActionList الخاص بك. من الواضح أن TextBox لا يعرف وجود AjaxControlToolkit، لذلك لا تتم إضافة "إضافة ملحق..." مثل DesignerActionMethodItem بواسطته. لذا، هل يوفر إطار عمل .net نوعًا من الواجهة التي تسمح لنا "بإدخال DesignerActionItem ديناميكيًا" في عناصر التحكم الأخرى؟
من خلال البحث في AjaxControlToolKit.dll، وجدت أن مصمم عناصر التحكم الموسعة هذه ليس مسؤولاً عن توفير إجراء "إضافة ملحق". مصمم نموذج الويب لـ Visual Studio تعال وادرس. استخدم العاكس لفتح 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 ComponentActions = 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: إذا (componentActions == null)
13: {
14: ComponentActions = new DesignerActionListCollection();
15: }
16: إرجاع ComponentActions؛
17: }
18:
19:
20:
واحد وعشرون:
من التعليمات البرمجية أعلاه، يمكنك أن ترى أنه يتم تحديد DesignerActionListCollection النهائي بواسطة GetComponentActions للفئة System.ComponentModel.Design.DesignerActionService ضمن تجميع System.Design، وMicrosoft.Web.Design.WebFormDesigner ضمن Microsoft.Web.Design.Client. dll.+WebDesignerActionService يرث هذه الفئة ويكون تنفيذها كما يلي:
1: تجاوز محمي GetComponentDesignerActions (مكون IComponent، قوائم إجراءات DesignerActionListCollection)
2: {
3: التحكم في التحكم = المكون كعنصر تحكم؛
4: ElementDesignerparent = null;
5: إذا (التحكم! = فارغ)
6: {
7: الأصل = ElementDesigner.GetElementDesigner(control);
8: }
9: إذا ((parent == null) || !parent.InTemplateMode)
10: {
11: base.GetComponentDesignerActions(component, actionLists);
12: إذا ((الوالد != فارغ) && (parent.Designer != خالي))
13: {
14: مصمم ControlDesigner =parent.Designer كـ ControlDesigner؛
15: إذا ((designer != null) && (designer.AutoFormats.Count > 0))
16: {
17: actionLists.Insert(0, new AutoFormatActionList(parent));
18: }
19: }
20: إذا ((الوالد != فارغ) && (parent.Element != فارغ))
الحادي والعشرون : {
22: IWebDataFormElementCallback dataFormElementCallback =parent.Element.GetDataFormElementCallback();
23: إذا (dataFormElementCallback != فارغة)
أربعة وعشرون: {
25: قائمة DataFormElementActionList = new DataFormElementActionList(parent,parent.Control, dataFormElementCallback);
26: actionLists.Add(list);
27: DataFormElementActionList.ModifyActionListsForListControl(actionLists, list);
28: }
29: }
30: إذا (((الأصل != فارغ) && (parent.Designer != null)) &&parent.DocumentDesigner.ExtenderControlHelper.ProvidesActionLists)
31: {
32:parent.DocumentDesigner.ExtenderControlHelper.AddActionLists(parent, actionLists);
33: }
34: }
35: إذا ((الوالد! = فارغ) && (parent.TemplateEditingUI != فارغ))
36: {
37: actionLists.Add(new TemplateEditingActionList(parent.TemplateEditingUI,parent.Element));
38: }
39: }
40:
41:
42:
43:
وفي هذه الطريقة توجد هذه الفقرة:
1: إذا (((الوالد != فارغ) && (parent.Designer != null)) &&parent.DocumentDesigner.ExtenderControlHelper.ProvidesActionLists)
2: {
3:parent.DocumentDesigner.ExtenderControlHelper.AddActionLists(parent, actionLists);
4: }
يبدو أنه تمت إضافة إجراء "إضافة ملحق" هنا. استمر في إلقاء نظرة على تنفيذ ExtenderControlHelper.AddActionLists:
1: AddActionLists باطلة عامة (عنصر ElementDesigner، قوائم DesignerActionListCollection)
2: {
3: lists.Add(new ControlExtenderActionList(element));
4: مكون ExtenderControl = element.Designer.Component مثل ExtenderControl؛
5: التحكم في التحكم = element.Designer.Component كعنصر تحكم؛
6: إذا ((مكون == فارغ) && (التحكم != فارغ))
7: {
8: خدمة IExtenderInformationService = (IExtenderInformationService) control.Site.GetService(typeof(IExtenderInformationService));
9: إذا (الخدمة! = فارغة)
10: {
11: foreach (تحكم التحكم 3 في الخدمة. GetAppliedExtenders (التحكم))
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 الخاص به ويتم تعريفه على النحو التالي:
1: التجاوز العام DesignerActionItemCollection GetSortedActionItems()
2: {
3: مكون التحكم = (التحكم) this._htmlDesigner.Component؛
4: عناصر DesignerActionItemCollection = new DesignerActionItemCollection();
5: خدمة IExtenderInformationService = (IExtenderInformationService) مكون.Site.GetService(typeof(IExtenderInformationService));
6: فئة السلسلة = SR.GetString(SR.Ids.SmartTasksLabelExtenderSection, CultureInfo.CurrentUICulture);
7: إذا (service.IsControlExtendible(مكون))
8: {
9: string DisplayName = SR.GetString(SR.Ids.SmartTasksAddExtender, CultureInfo.CurrentUICulture);
10: items.Add(new DesignerActionMethodItem(this, "AddExtender",displayName,category,true));
11: }
12: إذا (service.IsControlExtending(مكون))
13: {
14: string 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: تجاوز محمي GetComponentDesignerActions (مكون IComponent، قوائم إجراءات DesignerActionListCollection)
2: {
3: إذا (المكون == فارغ)
4: {
5: طرح ArgumentNullException("component");
6: }
7: إذا (قوائم الإجراءات == فارغة)
8: {
9: طرح ArgumentNullException("actionLists");
10: }
11: موقع IServiceContainer = Component.Site كـ IServiceContainer؛
12: إذا (الموقع! = فارغ)
13: {
14: خدمة DesignerCommandSet = (DesignerCommandSet) site.GetService(typeof(DesignerCommandSet));
15: إذا (الخدمة! = فارغة)
16: {
17: قوائم DesignerActionListCollection = Service.ActionLists;
18: إذا (القوائم != فارغة)
19: {
20: actionLists.AddRange(lists);
الحادي والعشرون: }
إثنان وعشرون: }
23: إذا ((actionLists.Count == 0) || ((actionLists.Count == 1) && (actionLists[0] is ControlDesigner.ControlDesignerActionList)))
أربعة وعشرون: {
25: أفعال DesignerVerbCollection = خدمة. أفعال؛
26: إذا ((الأفعال ! = فارغة) && (الأفعال. عدد ! = 0))
27: {
28: DesignerVerb[] array = new DesignerVerb[verbs.Count];
29: الأفعال.نسخ إلى(array, 0);
30: actionLists.Add(new DesignerActionVerbList(array));
31: }
32: }
33: }
34: }
35:
36:
37:
38:
من خلال دراسة الكود أعلاه، يمكننا أن نرى أنه يتم إرجاع DesignerActionListCollection بواسطة سمة ActionLists لخدمة DesignerCommandSet، ويتم الحصول على هذه الخدمة من موقع المكون طالما أنني أكتب DesignerCommandSet آخر، وتأكد من إخراج DesignerCommandSet من ملف الموقع لي فقط أكتب هذه الخدمة. أخيرًا تم العثور على نقطة الدخول، وهذه هي الطريقة المحددة.
أولاً، قم بإنشاء فئة ترث DesignerCommandSet، كما يلي:
1: الفئة العامة MyDesignerCommandSet: DesignerCommandSet
2: {
3: ComponentDesigner الخاص _componentDesigner؛
4:
5: MyDesignerCommandSet العام (ComponentDesigner ComponentDesigner)
6: {
7: _componentDesigner = ComponentDesigner;
8: }
9:
10: التجاوز العام لـ ICollection GetCommands (اسم السلسلة)
11: {
12: إذا (name.Equals("ActionLists"))
13: {
14: إرجاع GetActionLists();
15: }
16: إرجاع base.GetCommands(name);
17: }
18:
19: مصممActionListCollection الخاص GetActionLists()
20: {
21: // احصل على قوائم DesignerAction الأصلية لعنصر التحكم أولاً
22: قوائم DesignerActionListCollection = _componentDesigner.ActionLists;
ثلاثة وعشرين:
24: // أضف "إضافة إجراء" DesignerActionList
25: lists.Add(new ActionList(_componentDesigner));
26: قوائم العودة.
27: }
28:
29: قائمة الإجراءات الداخلية للفئة: DesignerActionList
30: {
31: إجراءات خاصة لـ DesignerActionItemCollection؛
32:
33: قائمة الإجراءات العامة (مصمم IDesigner)
34: : قاعدة (مصمم.مكون)
35: {
36: }
37: التجاوز العام DesignerActionItemCollection GetSortedActionItems()
38: {
39: إذا (_actions == فارغة)
40: {
41: سلسلة الإجراء constCategory = "الإجراءات"؛
42: _actions = new DesignerActionItemCollection();
43: _actions.Add(new DesignerActionMethodItem(this, "AddAction", "Add action...", actionCategory, true));
44: }
45: عودة _actions.
46: }
47:
48: الفراغ العام AddAction ()
49: {
50: //أضف منطق الإجراء، تم حذفه
51: }
52: }
53: }
الخطوة التالية هي كيفية جعل Site ServiceProvider للمكون يقوم بإرجاع الخدمة الخاصة به. تتمثل الطريقة في كتابة موقع بنفسك وجعل موقع المكون كائنًا من فئة SIte التي كتبتها.
تعريف فئة الموقع الذي كتبته هو كما يلي:
1: SiteProxy من الفئة العامة: ISite, IServiceContainer
2: {
3: موقع ISite_site الخاص؛
4: ComponentDesigner _designer الخاص؛
5:
6: SiteProxy العام (موقع ISite، مصمم ComponentDesigner)
7: {
8: _site = الموقع؛
9: _designer = مصمم؛
10:
11: }
12:
13: #منطقة أعضاء ISite
14:
15: IComponentComponent العام
16: {
17: احصل على {return _site.Component}؛
18: }
19:
20: حاوية System.ComponentModel.IContainer العامة
الحادي والعشرون : {
22: احصل على {return _site.Container}؛
ثلاثة وعشرين: }
أربعة وعشرون:
25: boolDesignMode العام
26: {
27: احصل على {return _site.DesignMode}؛
28: }
29:
30: اسم السلسلة العامة
31: {
32: احصل على {return _site.Name}؛
33: مجموعة { _site.Name = القيمة }
34: }
35:
36: #المنطقة
37:
38: #عضو مزود الخدمة بالمنطقة
39:
40: الكائن العام GetService (نوع الخدمة)
41: {
42: خدمة الكائن = _site.GetService(serviceType);
43:
44: إذا (serviceType == typeof(DesignerCommandSet) &&!(_designer.Component is ExtenderControl))
45: {
46: إذا (الخدمة == فارغة || !(الخدمة هي MyDesignerCommandSet))
47: {
48: إذا (الخدمة! = فارغة)
49: {
50: RemoveService(typeof(DesignerCommandSet));
51: }
52: // قم بإرجاع DesignerCommandSet الذي كتبته بنفسك
53: الخدمة = new MyDesignerCommandSet(_designer);
54: AddService(typeof(DesignerCommandSet),service);
55: }
56: }
57: خدمة العودة؛
58: }
59:
60: #المنطقة
61:
62: #عضو المنطقة IServiceContainer
63:
64: AddService باطلة عامة (اكتب نوع الخدمة، رد الاتصال ServiceCreatorCallback، الترويج المنطقي)
65: {
66: (_site as IServiceContainer).AddService(serviceType, callback, Promotion);
67: }
68:
69: AddService الفراغ العام (نوع الخدمة، رد الاتصال ServiceCreatorCallback)
70: {
71: (_site as IServiceContainer).AddService(serviceType, callback);
72: }
73:
74: AddService باطلة عامة (اكتب نوع الخدمة، كائن خدمة مثيل، تعزيز منطقي)
75: {
76: (_site as IServiceContainer).AddService(serviceType,serviceInstance,program);
77: }
78:
79: AddService الفراغ العام (اكتب نوع الخدمة، كائن خدمة مثيل)
80: {
81: (_site as IServiceContainer).AddService(serviceType,serviceInstance);
82: }
83:
84: إزالة الخدمة العامة (اكتب نوع الخدمة، الترويج المنطقي)
85: {
86: (_site as IServiceContainer).RemoveService(serviceType, Promotion);
87: }
88:
89: RemoveService الفراغ العام (اكتب نوع الخدمة)
90: {
91: (_site as IServiceContainer).RemoveService(serviceType);
92: }
93:
94 : #المنطقة
95: }
في طريقة GetService لهذا الموقع، حدد نوع الخدمة التي سيتم الحصول عليها إذا كانت DesignerCommandSet، فقم بإرجاع MyDesignerCommandSet الذي قمت بإنشائه.
الخطوة التالية هي كيفية تغيير موقع المكون إلى SiteProxy الذي تكتبه بنفسك. تتمثل إحدى الطرق في إضافة عنصر تحكم مخصص وتغيير موقع عناصر التحكم الأخرى في الحاوية في طريقة التهيئة الخاصة بـ ControlDesigner لعنصر التحكم. ما عليك سوى سحب عنصر التحكم إلى WebForm لتغيير موقع عناصر التحكم الأخرى؛ تتمثل الطريقة في كتابة حزمة مقابل والتقاط الأحداث المقابلة لمصمم نموذج الويب في الحزمة. يتم تقديم النهج الأول أدناه:
قم بإضافة عنصر تحكم جديد موروث من عنصر التحكم، يسمى ActionManager، ولا يحتاج عنصر التحكم هذا إلى إضافة أي وظائف، بل تحتاج فقط إلى إنشاء ControlDesigner له. الكود الرئيسي لفئة ControlDesigner هو كما يلي:
1: الفئة العامة ActionManagerDesigner: ControlDesigner
2: {
3: IDesignerHost _host الخاص؛
4: معرف خاص<IComponent, ISite> _components;
5:
6: تهيئة الفراغ العام للتجاوز (مكون IComponent)
7: {
8: base.Initialize(component);
9:
10: _components = new Dictionary<IComponent, ISite>();
11:
12: _host = GetService(typeof(IDesignerHost)) as IDesignerHost;
13: إذا (_host != فارغة)
14: {
15: // استبدل الموقع بعناصر التحكم الموجودة
16: ProcessComponent();
17:
18: خدمة IComponentChangeService =
19: _host.GetService(typeof(IComponentChangeService)) كـ IComponentChangeService;
20: إذا (الخدمة! = فارغة)
الحادي والعشرون : {
22:service.ComponentAdded += ComponentAdded;
23:service.ComponentRemoving += ComponentRemoving;
أربعة وعشرون : }
25: }
26: }
27:
28: #مكون_عملية_المنطقة
29:
30: ProcessComponent () الفراغ الخاص
31: {
32: مكونات ComponentCollection = _host.Container.Components;
33: foreach (مكون IComponent في المكونات)
34: {
35: إذا (المكون هو ActionControl)
36: تابع؛
37: ProcessComponentSite(component);
38: }
39: }
40:
41: #المنطقة
42:
43: #منطقة استبدال الموقع
44:
45: /// <الملخص>
46: /// استبدل موقع المكون الأصلي بـ SiteProxy
47: /// </الملخص>
48: موقع ProcessComponentSite الخاص (مكون IComponent)
49: {
50: مصمم ComponentDesigner = _host.GetDesigner(component) as ComponentDesigner;
51: _components[component] = Component.Site;
52: Component.Site = new SiteProxy(component.Site, Designer);
53: }
54:
55: /// <الملخص>
56: /// استعادة الموقع الأصلي للمكون
57: /// </الملخص>
58: /// <param name="component"></param>
59: موقع RestoreComponentSite الخاص (مكون IComponent)
60: {
61: إذا (_components.ContainsKey(مكون))
62: {
63: موقع ISite = _components[component];
64: مكون. الموقع = الموقع؛
65: _components.Remove(component);
66: }
67: }
68:
69 : #المنطقة
70:
71: # المنطقة على المكون إضافة وإزالة وتغيير
72:
73: ComponentRemoving باطلة خاصة (مرسل الكائن، ComponentEventArgs e)
74: {
75: إذا (e.Component هو ActionControl)
76: {
77 : العودة.
78: }
79: // عند حذف مكون، يجب استعادة خاصية الموقع الخاصة به، وإلا سيبقى الموقع الأصلي في DesignerHost.
80: // عند إضافة مكون بنفس الاسم بهذه الطريقة، سيتم الإبلاغ عن خطأ "اسم مكون مكرر".
81: RestoreComponentSite(e.Component);
82: }
83:
84:
85: إضافة مكون باطل خاص (مرسل الكائن، ComponentEventArgs e)
86: {
87: إذا (e.Component هو ActionControl)
88: {
89 : العودة.
90: }
91: ProcessComponentSite(e.Component);
92: }
93:
94 : #المنطقة
95:
96 : #منطقة التخلص
97:
98: التخلص من باطلة التجاوز المحمي (التخلص المنطقي)
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: قاعدة.التخلص(التخلص)؛
111: }
112:
113 : #المنطقة
114: }
في هذه المرحلة، طالما قمت بسحب عنصر تحكم ActionManager إلى مصمم نموذج الويب، يمكنك رؤية الرابط "إضافة إجراء..." على لوحة المهام الذكية لعناصر التحكم الأخرى. ومع ذلك، تتطلب هذه الطريقة وضع عنصر تحكم إضافي في مصمم نموذج الويب. عنصر التحكم هذا مفيد فقط في وقت التصميم وغير مفيد في وقت التشغيل. يبدو الأمر غريبًا، لذا فإن أفضل طريقة هي الطريقة الثانية، وهي تطوير حزمة مقابل. في طريقة تهيئة الحزمة، قم بتسجيل حدث DesignerCreated الخاص بـ IDesignerEventService، ثم حقق الغرض من تغيير موقع التحكم من خلال IDesignerHost وIComponentChangeService. التنفيذ المحدد مشابه لما ورد أعلاه، لذلك لن أكتبه بعد الآن.