Pustaka kontrol Ajax Control Toolkit berisi beberapa kontrol yang diperluas. Dengan menggunakan kontrol yang diperluas ini, Anda dapat dengan mudah menambahkan efek Ajax ke kontrol biasa. Misalnya, Anda dapat menggunakan kontrol AutoCompleteExtender untuk menambahkan efek ajax penyelesaian otomatis ke kotak teks. Tentu bukan hal tersebut yang ingin dibahas dalam artikel ini.
Tambahkan Ajax Control Toolkit ke toolbox Visual Studio 2008, buka file aspx baru, dan seret TextBox ke dalamnya. Saat ini, sesuatu yang menarik terjadi. Di panel SmartTasks di TextBox, tautan ke "Tambahkan ekstensi..." benar-benar muncul! Saya mencoba menyeret Tombol dan Panel lagi, dan tanpa kecuali, tautan "Tambahkan Ekstensi..." muncul di bagian bawah panel SmartTasks pada setiap kontrol.
Baru-baru ini, saya berencana untuk mengabstraksi fungsi seperti menyimpan, menghapus, dan menutup halaman menjadi tindakan. Setiap tindakan sesuai dengan kontrol Web khusus. Setelah melampirkan kontrol tindakan ke kontrol target (seperti Tombol), kontrol target akan memiliki Fungsi seperti menyimpan, menghapus, dan menutup halaman. Bagaimana cara melampirkan tindakan dengan mudah ke kontrol Tombol di desainer WebForm? Yang saya inginkan adalah sesuatu seperti "Tambahkan ekstensi...".
Teman yang telah mengembangkan kontrol server khusus harus mengetahui bahwa jika Anda ingin menambahkan SmartTasks ke kontrol, Anda perlu mengganti properti ActionLists dari ControlDesigner dan mengimplementasikan DesignerActionList Anda sendiri. Jelas, TextBox tidak mengetahui keberadaan AjaxControlToolkit, jadi "Tambahkan ekstensi..." DesignerActionMethodItem tersebut tidak ditambahkan olehnya. Jadi, apakah kerangka .net menyediakan semacam antarmuka yang memungkinkan kita "menyuntikkan secara dinamis" DesignerActionItem ke kontrol lain?
Melalui penelitian di AjaxControlToolKit.dll, saya menemukan bahwa Perancang kontrol yang diperluas ini tidak bertanggung jawab untuk menyediakan Tindakan "Tambahkan ekstensi". Mereka hanya bertanggung jawab untuk menyediakan konten ekstensi yang sesuai dengan ekstensi yang sesuai, jadi satu-satunya entri adalah dari desainer formulir web dari Visual studio. Datang dan belajar. Gunakan reflektor untuk membuka Microsoft Visual Studio 9.0Common7IDEMicrosoft.Web.Design.Client.dll dan temukan antarmuka IWebSmartTasksProvider. Antarmuka ini memiliki metode GetDesignerActionLists . Antarmuka ini memiliki tiga kelas implementasi, DataFormDesigner, DataFormXslValueOfDesigner, dan ElementDesigner. Dari penamaan ketiga kelas ini dapat disimpulkan bahwa ElementDesigner seharusnya menjadi kelas implementasi yang paling umum digunakan. Metode GetDesignerActionLists dari ElementDesigner diimplementasikan sebagai berikut:
1: DesignerActionListCollection IWebSmartTasksProvider.GetDesignerActionLists()
2: {
3: DesignerActionListCollection komponenActions = null;
4: jika (ini.Desainer!= null)
5: {
6: Layanan DesignerActionService = (DesignerActionService) base.DesignerHost.GetService(typeof(DesignerActionService));
7: jika (layanan!= null)
8: {
9: komponenActions = layanan.GetComponentActions(ini.Desainer.Komponen);
10: }
11: }
12: jika (componentActions == null)
13: {
14: komponenActions = new DesignerActionListCollection();
15: }
16: mengembalikan komponenActions;
17: }
18:
19:
20:
dua puluh satu:
Dari kode di atas, Anda dapat melihat bahwa DesignerActionListCollection akhir ditentukan oleh GetComponentActions dari kelas System.ComponentModel.Design.DesignerActionService di bawah rakitan System.Design, dan Microsoft.Web.Design.WebFormDesigner di bawah Microsoft.Web.Design.Client. dll.+WebDesignerActionService mewarisi kelas ini dan implementasinya adalah sebagai berikut:
1: penggantian yang dilindungi batal GetComponentDesignerActions (Komponen IComponent, Daftar tindakan DesignerActionListCollection)
2: {
3: Kontrol kontrol = komponen sebagai Kontrol;
4: Induk ElementDesigner = null;
5: jika (kontrol!= null)
6: {
7: induk = ElementDesigner.GetElementDesigner(kontrol);
8: }
9: if ((parent == null) || !parent.InTemplateMode)
10: {
11: base.GetComponentDesignerActions(komponen, daftar tindakan);
12: if ((parent != null) && (parent.Designer != null))
13: {
14: Perancang ControlDesigner = parent.Designer sebagai ControlDesigner;
15: if ((desainer != null) && (desainer.AutoFormats.Count > 0))
16: {
17: actionLists.Insert(0, AutoFormatActionList(induk) baru);
18: }
19: }
20: if ((parent != null) && (parent.Element != null))
dua puluh satu: {
22: IWebDataFormElementCallback dataFormElementCallback = induk.Element.GetDataFormElementCallback();
23: jika (dataFormElementCallback!= null)
dua puluh empat: {
25: Daftar DataFormElementActionList = DataFormElementActionList baru(induk, induk.Kontrol, dataFormElementCallback);
26: actionLists.Tambahkan(daftar);
27: DataFormElementActionList.ModifyActionListsForListControl(actionLists, daftar);
28: }
29: }
30: if (((parent != null) && (parent.Designer != null)) && parent.DocumentDesigner.ExtenderControlHelper.ProvidesActionLists)
31: {
32: parent.DocumentDesigner.ExtenderControlHelper.AddActionLists(parent, actionLists);
33: }
34: }
35: if ((parent != null) && (parent.TemplateEditingUI != null))
36: {
37: actionLists.Add(new TemplateEditingActionList(parent.TemplateEditingUI, parent.Element));
38: }
39: }
40:
41:
42:
43:
Dalam metode ini, ada paragraf ini:
1: if (((parent != null) && (parent.Designer != null)) && parent.DocumentDesigner.ExtenderControlHelper.ProvidesActionLists)
2: {
3: parent.DocumentDesigner.ExtenderControlHelper.AddActionLists(parent, actionLists);
4: }
Tampaknya tindakan "Tambahkan ekstensi" ditambahkan di sini. Lanjutkan melihat implementasi ExtenderControlHelper.AddActionLists:
1: public void AddActionLists (elemen ElementDesigner, daftar DesignerActionListCollection)
2: {
3: list.Add(new ControlExtenderActionList(elemen));
4: Komponen ExtenderControl = elemen.Designer.Component sebagai ExtenderControl;
5: Kontrol kontrol = elemen.Desainer.Komponen sebagai Kontrol;
6: if ((komponen == null) && (kontrol != null))
7: {
8: Layanan IExtenderInformationService = (IExtenderInformationService) control.Site.GetService(typeof(IExtenderInformationService));
9: jika (layanan!= null)
10: {
11: foreach (Kontrol control3 di service.GetAppliedExtenders(kontrol))
12: {
13: list.Add(new HoistedExtenderActionList(element.Designer, control3));
14: }
15: }
16: }
17: }
18:
19:
20:
dua puluh satu:
Kalimat pertama dalam metode ini adalah list.Add(new ControlExtenderActionList(element)). ControlExtenderActionList mewarisi System.ComponentModel.Design.DesignerActionList. Metode GetSortedActionItems didefinisikan sebagai berikut:
1: penggantian publik DesignerActionItemCollection GetSortedActionItems()
2: {
3: Komponen kontrol = (Kontrol) this._htmlDesigner.Component;
4: Item DesignerActionItemCollection = DesignerActionItemCollection baru();
5: IExtenderInformationService service = (IExtenderInformationService) komponen.Site.GetService(typeof(IExtenderInformationService));
6: kategori string = SR.GetString(SR.Ids.SmartTasksLabelExtenderSection, CultureInfo.CurrentUICulture);
7: if (service.IsControlExtendible(komponen))
8: {
9: string displayName = SR.GetString(SR.Ids.SmartTasksAddExtender, CultureInfo.CurrentUICulture);
10: items.Add(new DesignerActionMethodItem(ini, "AddExtender", displayName, kategori, true));
11: }
12: if (service.IsControlExended(komponen))
13: {
14: string str3 = SR.GetString(SR.Ids.SmartTasksRemoveExtender, CultureInfo.CurrentUICulture);
15: items.Add(new DesignerActionMethodItem(ini, "RemoveExtender", str3, kategori, true));
16: }
17: mengembalikan barang;
18: }
19:
Sekarang jelas bahwa tindakan "Tambahkan ekstensi" dikodekan secara keras di perancang formulir web Visual studio. Kerangka .net tidak menyediakan antarmuka yang sesuai bagi kami untuk menambahkan tindakan serupa. Tetapi efek yang saya inginkan adalah menambahkan tindakan "tambahkan tindakan", jadi saya tidak bisa merujuk ke metode AjaxControlToolkit untuk mencapainya.
Kembali dan periksa kembali metode GetComponentActions kelas Microsoft.Web.Design.WebFormDesigner+WebDesignerActionService dan temukan definisi kelas dasar System.Web.UI.Design.WebFormsDesignerActionService (di bawah rakitan System.Design), sebagai berikut:
1: penggantian yang dilindungi batal GetComponentDesignerActions (Komponen IComponent, Daftar tindakan DesignerActionListCollection)
2: {
3: jika (komponen == null)
4: {
5: lempar ArgumentNullException("component");
6: }
7: jika (daftar tindakan == nol)
8: {
9: lempar ArgumentNullException baru("actionLists");
10: }
11: Situs IServiceContainer = komponen.Situs sebagai IServiceContainer;
12: jika (situs!= null)
13: {
14: Layanan DesignerCommandSet = (DesignerCommandSet) situs.GetService(typeof(DesignerCommandSet));
15: jika (layanan!= null)
16: {
17: Daftar DesignerActionListCollection = layanan.ActionLists;
18: if (daftar != null)
19: {
20: actionLists.AddRange(daftar);
dua puluh satu: }
dua puluh dua: }
23: if ((actionLists.Count == 0) || ((actionLists.Count == 1) && (actionLists[0] adalah ControlDesigner.ControlDesignerActionList)))
dua puluh empat: {
25: Kata kerja DesignerVerbCollection = layanan.Kata Kerja;
26: if ((kata kerja != null) && (kata kerja.Hitung != 0))
27: {
28: DesignerVerb[] array = DesignerVerb[verbs.Count] baru;
29: kata kerja.CopyTo(array, 0);
30: actionLists.Add(new DesignerActionVerbList(array));
31: }
32: }
33: }
34: }
35:
36:
37:
38:
Dengan mempelajari kode di atas, kita dapat melihat bahwa DesignerActionListCollection dikembalikan oleh atribut ActionLists dari layanan DesignerCommandSet, dan layanan ini diperoleh dari Situs komponen. Selama saya menulis DesignerCommandSet lain, dan memastikan bahwa DesignerCommandSet diambil dari Situs ini milik saya. Tulis saja layanan ini. Akhirnya menemukan titik masuknya, inilah metode spesifiknya.
Pertama, buat kelas yang mewarisi DesignerCommandSet, sebagai berikut:
1: kelas publik MyDesignerCommandSet : DesignerCommandSet
2: {
3: ComponentDesigner _componentDesigner pribadi;
4:
5: MyDesignerCommandSet publik(ComponentDesigner komponenDesigner)
6: {
7: _componentDesigner = komponenDesigner;
8: }
9:
10: penggantian publik ICollection GetCommands (nama string)
11: {
12: if (nama.Sama dengan("Daftar Tindakan"))
13: {
14: kembalikan GetActionLists();
15: }
16: kembalikan base.GetCommands(nama);
17: }
18:
19: DesignerActionListCollection GetActionLists() pribadi
20: {
21: //Dapatkan DesignerActionLists asli dari kontrolnya terlebih dahulu
22: Daftar DesignerActionListCollection = _componentDesigner.ActionLists;
dua puluh tiga:
24: //Tambahkan DesignerActionList "Tambahkan Tindakan".
25: daftar.Tambahkan(Daftar Aksi baru(_componentDesigner));
26: daftar pengembalian;
27: }
28:
29: kelas internal ActionList : DesignerActionList
30: {
31: DesignerActionItemCollection _actions pribadi;
32:
33: Daftar Aksi publik (desainer IDesigner)
34: : dasar(desainer.Komponen)
35: {
36: }
37: penggantian publik DesignerActionItemCollection GetSortedActionItems()
38: {
39: jika (_tindakan == nol)
40: {
41: string const actionCategory = "Tindakan";
42: _actions = baru DesignerActionItemCollection();
43: _actions.Add(new DesignerActionMethodItem(ini, "AddAction", "Tambahkan tindakan...", actionCategory, true));
44: }
45: kembalikan _tindakan;
46: }
47:
48: pembatalan publik AddAction()
49: {
50: //Tambahkan logika tindakan, dihilangkan
51: }
52: }
53: }
Langkah selanjutnya adalah bagaimana membuat Site ServiceProvider komponen mengembalikan layanannya sendiri. Metodenya adalah dengan menulis Situs sendiri dan menjadikan Situs Komponen sebagai objek kelas SIte yang Anda tulis.
Definisi kelas Site yang saya tulis adalah sebagai berikut:
1: SiteProxy kelas publik : ISite, IServiceContainer
2: {
3: situs_ISite_pribadi;
4: ComponentDesigner _designer pribadi;
5:
6: SiteProxy publik (Situs ISite, desainer ComponentDesigner)
7: {
8: _situs = situs;
9: _desainer = desainer;
10:
11: }
12:
13: #anggota ISite wilayah
14:
15: IComponentComponent publik
16: {
17: dapatkan { return _site.Component }
18: }
19:
20: Kontainer System.ComponentModel.IContainer publik
dua puluh satu: {
22: dapatkan { return _site.Container;
dua puluh tiga: }
dua puluh empat:
25: boolDesignMode publik
26: {
27: dapatkan { return _site.DesignMode;
28: }
29:
30: nama string publik
31: {
32: dapatkan { return _site.Name }
33: setel { _situs.Nama = nilai }
34: }
35:
36: #wilayah akhir
37:
38: #anggota IServiceProvider wilayah
39:
40: objek publik GetService(Jenis serviceType)
41: {
42: layanan objek = _site.GetService(serviceType);
43:
44: if (serviceType == typeof(DesignerCommandSet) && !(_designer.Component adalah ExtenderControl))
45: {
46: if (layanan == null || !(layanan adalah MyDesignerCommandSet))
47: {
48: jika (layanan!= null)
49: {
50: HapusLayanan(typeof(DesignerCommandSet));
51: }
52: //Kembalikan DesignerCommandSet yang Anda tulis sendiri
53: layanan = baru MyDesignerCommandSet(_designer);
54: AddService(typeof(DesignerCommandSet), layanan);
55: }
56: }
57: layanan pengembalian;
58: }
59:
60: #wilayah akhir
61:
62: #anggota IServiceContainer wilayah
63:
64: public void AddService (Ketik serviceType, panggilan balik ServiceCreatorCallback, promosi bool)
65: {
66: (_site sebagai IServiceContainer).AddService(serviceType, callback, promo);
67: }
68:
69: public void AddService (Ketik serviceType, panggilan balik ServiceCreatorCallback)
70: {
71: (_site sebagai IServiceContainer).AddService(serviceType, callback);
72: }
73:
74: public void AddService(Ketik serviceType, objek serviceInstance, bool promo)
75: {
76: (_site sebagai IServiceContainer).AddService(serviceType, serviceInstance, promo);
77: }
78:
79: public void AddService(Jenis serviceType, objek serviceInstance)
80: {
81: (_situs sebagai IServiceContainer).AddService(serviceType, serviceInstance);
82: }
83:
84: public void HapusLayanan(Ketik serviceType, bool promo)
85: {
86: (_situs sebagai IServiceContainer).RemoveService(serviceType, promosikan);
87: }
88:
89: public void HapusLayanan(Jenis tipe layanan)
90: {
91: (_situs sebagai IServiceContainer).RemoveService(serviceType);
92: }
93:
94: #wilayah akhir
95: }
Dalam metode GetService Situs ini, tentukan jenis layanan yang akan diperoleh. Jika itu adalah DesignerCommandSet, kembalikan MyDesignerCommandSet yang Anda buat.
Langkah selanjutnya adalah bagaimana mengubah Site komponen menjadi SiteProxy yang Anda tulis sendiri. Salah satu metodenya adalah dengan menambahkan kontrol khusus dan mengubah Situs kontrol lain di Kontainer dalam metode Inisialisasi ControlDesigner kontrol tersebut Metodenya adalah dengan menulis paket vs dan menangkap peristiwa terkait dari perancang formulir web dalam paket tersebut. Pendekatan pertama diperkenalkan di bawah ini:
Tambahkan kontrol baru yang diwarisi dari Kontrol, yang disebut ActionManager. Kontrol ini tidak perlu menambahkan fungsi apa pun. Kode utama kelas ControlDesignernya adalah sebagai berikut:
1: kelas publik ActionManagerDesigner : ControlDesigner
2: {
3: IDesignerHost _host pribadi;
4: IDictionary pribadi<IComponent, ISite> _components;
5:
6: public override void Inisialisasi (komponen IComponent)
7: {
8: base.Inisialisasi(komponen);
9:
10: _components = Kamus baru<IComponent, ISite>();
11:
12: _host = GetService(typeof(IDesignerHost)) sebagai IDesignerHost;
13: jika (_host != nol)
14: {
15: //Ganti Situs dengan kontrol yang ada
16: Komponen Proses();
17:
18: Layanan IComponentChangeService =
19: _host.GetService(typeof(IComponentChangeService)) sebagai IComponentChangeService;
20: jika (layanan!= null)
dua puluh satu: {
22: layanan.KomponenDitambahkan += KomponenDitambahkan;
23: service.ComponentRemoving += ComponentRemoving;
dua puluh empat: }
25: }
26: }
27:
28: #KomponenProseswilayah
29:
30: Komponen Proses kekosongan pribadi()
31: {
32: Komponen ComponentCollection = _host.Container.Components;
33: foreach (Komponen IKomponen dalam komponen)
34: {
35: if (komponennya adalah ActionControl)
36: lanjutkan;
37: Situs Komponen Proses(komponen);
38: }
39: }
40:
41: #wilayah akhir
42:
43: #region ganti Situs
44:
45: /// <ringkasan>
46: /// Ganti Situs Komponen asli dengan SiteProxy
47: /// </ringkasan>
48: private void ProcessComponentSite (komponen IComponent)
49: {
50: Perancang ComponentDesigner = _host.GetDesigner(komponen) sebagai ComponentDesigner;
51: _components[component] = komponen.Situs;
52: komponen.Situs = SiteProxy baru(komponen.Situs, perancang);
53: }
54:
55: /// <ringkasan>
56: /// Memulihkan situs asli Komponen
57: /// </ringkasan>
58: /// <param nama="komponen"></param>
59: private void RestoreComponentSite (komponen IComponent)
60: {
61: jika (_components.ContainsKey(komponen))
62: {
63: Situs ISite = _components[component];
64: komponen.Situs = situs;
65: _components.Hapus(komponen);
66: }
67: }
68:
69: #wilayah akhir
70:
71: #region pada Komponen Tambahkan, hapus, ubah
72:
73: private void ComponentRemoving (pengirim objek, ComponentEventArgs e)
74: {
75: if (e.Komponen adalah ActionControl)
76: {
77: kembali;
78: }
79: //Saat menghapus Komponen, properti Situsnya harus dipulihkan, jika tidak, Situs asli akan tetap berada di DesignerHost.
80: //Saat menambahkan Komponen dengan nama yang sama dengan cara ini, kesalahan "duplikat nama komponen" akan dilaporkan.
81: RestoreComponentSite(e.Komponen);
82: }
83:
84:
85: private void ComponentAdded (pengirim objek, ComponentEventArgs e)
86: {
87: if (e.Komponen adalah ActionControl)
88: {
89: kembali;
90: }
91: ProcessComponentSite (e.Komponen);
92: }
93:
94: #wilayah akhir
95:
96: #pembuangan wilayah
97:
98: penggantian yang dilindungi batal Buang (pembuangan bool)
99: {
100: jika (_host != nol)
101: {
102: Layanan IComponentChangeService =
103: _host.GetService(typeof(IComponentChangeService)) sebagai IComponentChangeService;
104: jika (layanan!= null)
105: {
106: layanan.ComponentAdded -= ComponentAdded;
107: layanan.ComponentRemoving -= ComponentRemoving;
108: }
109: }
110: base.Dispose(membuang);
111: }
112:
113: #wilayah akhir
114: }
Pada titik ini, selama Anda menyeret kontrol ActionManager ke perancang formulir web, Anda bisa melihat tautan "Tambahkan Tindakan..." di panel tugas cerdas kontrol lainnya. Namun, metode ini memerlukan penempatan kontrol tambahan di perancang formulir web. Kontrol ini hanya berguna pada waktu desain dan tidak berguna saat runtime, jadi pendekatan terbaik adalah pendekatan kedua, yaitu mengembangkan paket vs. dalam metode Inisialisasi paket, daftarkan acara DesignerCreated dari IDesignerEventService, dan kemudian capai tujuan mengubah Situs kontrol melalui IDesignerHost dan IComponentChangeService. Implementasi spesifiknya mirip dengan di atas, jadi saya tidak akan menulisnya lagi.