.Net开发笔记(十九) 创建一个可以可视化设计的对象
閱讀本篇博客之前需要了解VS窗體設(shè)計(jì)器的工作原理,詳細(xì)可參見(jiàn)本系列博客(十)、(十一)、(十二)。必須需要知道的一條結(jié)論就是:處于窗體設(shè)計(jì)器(Form Designer)中的任何組件(包含控件,下同),都是實(shí)際存在的一個(gè)實(shí)例。也就是說(shuō),拖進(jìn)去的button1,其實(shí)就是實(shí)例化一個(gè)Button控件。
通常編碼中,我們?cè)谑褂靡粋€(gè)類型對(duì)象時(shí),通過(guò)以下方式:
?View Code如上所示,我們?cè)谑褂肅ar類時(shí),是通過(guò)new的方式來(lái)創(chuàng)建一個(gè)實(shí)例,然后給它初始化一些信息,這些所有操作都是通過(guò)我們手動(dòng)來(lái)編寫代碼實(shí)現(xiàn)的。
我們注意到,在設(shè)計(jì)UI界面的時(shí)候,窗體中的所有控件、組件都是可以通過(guò)“屬性窗體”來(lái)編輯的,也就是說(shuō),界面上這些元素的初始化不需要我們手動(dòng)編寫代碼,完全可以通過(guò)點(diǎn)點(diǎn)鼠標(biāo),按按鍵盤就可以做到。我們可以總結(jié)出來(lái)設(shè)計(jì)器可以幫我們做以下工作:
- 實(shí)例化對(duì)象
? ? 沒(méi)錯(cuò),不用你手動(dòng)new對(duì)象了,設(shè)計(jì)器幫你來(lái)完成。
- 編輯屬性
? ? 選定一個(gè)組件,在屬性窗體中編輯它的屬性,跟你通過(guò)編寫“實(shí)例.屬性=屬性值”是一樣的效果。
- 注冊(cè)事件
? ? 選定一個(gè)組件,在屬性窗體的事件選項(xiàng)卡,雙擊事件空白處,自動(dòng)注冊(cè)事件。
窗體設(shè)計(jì)器不需要你手動(dòng)編寫一行代碼,對(duì)象的實(shí)例化、屬性編輯、事件注冊(cè)全部搞定,也就是說(shuō),窗體設(shè)計(jì)器能夠可視化設(shè)計(jì)一些對(duì)象。至于哪些類型的對(duì)象可以通過(guò)窗體設(shè)計(jì)器來(lái)進(jìn)行可視化設(shè)計(jì),請(qǐng)參見(jiàn)本系列(十、十一、十二),我在這里直接給出結(jié)果:窗體設(shè)計(jì)器能夠可視化設(shè)計(jì)實(shí)現(xiàn)了IComponent接口類型的對(duì)象。也就是說(shuō),如果你定義了一個(gè)類型A,恰好它實(shí)現(xiàn)了IComponent接口(直接或者間接),那么你就完全可以通過(guò)窗體設(shè)計(jì)器來(lái)可視化設(shè)計(jì)A類型的對(duì)象。
由此可以看出,創(chuàng)建一個(gè)可以可視化設(shè)計(jì)的對(duì)象并不難,只要我們的類型實(shí)現(xiàn)了IComponent接口就行(官方稱這種類型為組件)。我們?cè)賮?lái)看一下,窗體設(shè)計(jì)器初始化出來(lái)的對(duì)象,跟我們自己手動(dòng)編寫代碼初始化的對(duì)象有哪些相同點(diǎn)和不同點(diǎn):
不同點(diǎn):
- 前者更直觀簡(jiǎn)單,隱藏的東西太多,后者復(fù)雜,但是清楚內(nèi)部過(guò)程。
- 前者對(duì)象的初始化,在程序一啟動(dòng)就開(kāi)始,不能人工控制其時(shí)機(jī),具體是在Form1的構(gòu)造方法中的InitializeComponent()中進(jìn)行,后者就更靈活,需要的時(shí)候編寫代碼就可以。
- 前者初始化出來(lái)的對(duì)象幾乎都跟UI界面有關(guān)(這個(gè)很容易就能想到,窗體設(shè)計(jì)器肯定設(shè)計(jì)跟窗體界面有關(guān)的東西),而后者沒(méi)有這個(gè)原則,不管是什么對(duì)象,都是可以的。
相同點(diǎn):
- 都是初始化一個(gè)對(duì)象。
- 都有代碼產(chǎn)生,前者產(chǎn)生的代碼在InitializeComponent()中,后者為人工編寫。
我們應(yīng)該清楚,程序最終都是要經(jīng)過(guò)將源代碼編譯成可執(zhí)行文件之后才能運(yùn)行的,所以源代碼是一切根本,沒(méi)有源代碼,其他的都是白扯。
綜上所有之述,我們可以手動(dòng)編寫代碼來(lái)初始化任何對(duì)象,我們可以通過(guò)窗體設(shè)計(jì)器來(lái)初始化實(shí)現(xiàn)了IComponent接口的類型對(duì)象。
好了知道怎樣才能創(chuàng)建一個(gè)可以可視化設(shè)計(jì)的對(duì)象之后,我們來(lái)創(chuàng)建一個(gè)試一下,定義一個(gè)類型MyComponent,使其繼承自Component:
?View Code如上代碼所示,該類型只包含了幾個(gè)公共屬性,沒(méi)有其他內(nèi)容。此類型對(duì)象就可以通過(guò)窗體設(shè)計(jì)器來(lái)設(shè)計(jì)了,也就是說(shuō),從工具箱中向設(shè)計(jì)器中拖放MyComponent類型之后,窗體設(shè)計(jì)器自動(dòng)會(huì)實(shí)例化一個(gè)MyComponent對(duì)象,并且你可以通過(guò)屬性窗體來(lái)編輯該對(duì)象的屬性:
1)StringProperty
? ? ?String類型屬性,直接可以在屬性窗體中輸入。
2)ColorProperty
? ? ?Color類型屬性,屬于.NET自帶類型,所以有默認(rèn)的屬性編輯器,如下圖:
圖1
3)MyTypeProperty1
? ? 自定義類型屬性,需要我們自己定義一個(gè)屬性編輯器Editor(typeof(MyTypeEditor1),typeof(UITypeEditor))。
4)MyTypeProperty2
? ? 自定義類型屬性,需要我們自己定義一個(gè)屬性編輯器Editor(typeof(MyTypeEditor2),typeof(UITypeEditor))。
5)ControlProperty
? ? Control類型屬性,我們可以將設(shè)計(jì)器中已經(jīng)存在的Control賦值給該屬性,指定了屬性編輯器Editor(typeof(ControlEditor),typeof(UITypeEditor))。
6)ImageListProperty
? ? ImageList屬性,這個(gè)就是我們常見(jiàn)的一些控件(比如TabControl)含有ImageList屬性,點(diǎn)擊右方的小三角形,就可以列出窗體設(shè)計(jì)器中已經(jīng)存在的ImageList,供你選擇。指定了屬性編輯器Editor(typeof(ImageListEditor),typeof(UITypeEditor))。
也就是說(shuō),當(dāng)我們?cè)诖绑w設(shè)計(jì)器中設(shè)計(jì)一個(gè)對(duì)象的時(shí)候,如果該對(duì)象包含一些特殊(非.NET默認(rèn)自帶類型)類型屬性時(shí),我們需要為該屬性提供一個(gè)“屬性編輯器”。
以下就分別為每個(gè)屬性對(duì)應(yīng)的屬性編輯器了(假設(shè)諸位看官都知道了UITypeEditor的作用,不知道可以查一下):
1)MyTypeProperty1屬性
?View Code鼠標(biāo)點(diǎn)擊MyTypeProperty1屬性右側(cè)的小三角形,出現(xiàn)一個(gè)下拉列表框。如下圖:
圖2
2)MyTypeProperty2屬性
?View Code鼠標(biāo)點(diǎn)擊MyTypeProperty2右側(cè)的小三角形,彈出一個(gè)對(duì)話框。
圖3
3)ControlProperty屬性
?View Code鼠標(biāo)點(diǎn)擊ControlProperty右側(cè)的小三角形,出現(xiàn)下拉列表框,列表中顯示的都是窗體設(shè)計(jì)器中已經(jīng)存在的Control。
圖4
4)ImageListProperty屬性
?View Code鼠標(biāo)點(diǎn)擊ImageListProperty右側(cè)的小三角形,出現(xiàn)下拉列表,列表中顯示窗體設(shè)計(jì)器中已經(jīng)存在的ImageList。
圖5
本篇博客介紹了怎么創(chuàng)建一個(gè)可以可視化設(shè)計(jì)的對(duì)象(準(zhǔn)確來(lái)講,應(yīng)該是怎樣創(chuàng)建一個(gè)可以可視化設(shè)計(jì)其對(duì)象的類型),首先讓類型(間接或者直接)實(shí)現(xiàn)IComponent接口(不要問(wèn)我為什么,請(qǐng)參見(jiàn)前面的博客),然后為類型的某些特殊屬性創(chuàng)建對(duì)應(yīng)的屬性編輯器,就這么簡(jiǎn)單。類型創(chuàng)建者工作量大一點(diǎn),但是類型使用者更方便一些,Demo中MyComponent類型就是最后的核心成果,供使用者使用,使用者不需要知道其他的類似屬性編輯器之類的東西,在他們看來(lái),這些相當(dāng)于沒(méi)有。
注意使用范圍,并不是任何時(shí)候都可以使用,最好參見(jiàn)前面提到的“相同點(diǎn)”和“不同點(diǎn)”那里。另外,本篇博客中設(shè)計(jì)到的知識(shí)點(diǎn)很多,像provider.GetService(typeof(IWindowsFormsEditorService))、foreach(Component c in context.Container.Components)這些需要和設(shè)計(jì)器打交道的地方我?guī)缀鯖](méi)有詳細(xì)說(shuō)到過(guò),原因是這些太復(fù)雜了,要是細(xì)說(shuō)的話,得說(shuō)一大簍子,而且不是本篇文章的重點(diǎn)。
源碼下載地址:http://files.cnblogs.com/xiaozhi_5638/PropertyEditorInDesigner.rar
注意不要試圖運(yùn)行源代碼,沒(méi)有任何效果,只能在設(shè)計(jì)器中看到效果。希望有幫助。
Update (2013-12-09)
上面結(jié)束提到了“支持可視化設(shè)計(jì)對(duì)象”的使用場(chǎng)合,建議如果該類型跟UI界面有關(guān)聯(lián)(需要與界面其他元素交互),并且對(duì)象的實(shí)例化不需要人工控制其時(shí)機(jī),那么可以讓該類型支持可視化設(shè)計(jì)(也就是實(shí)現(xiàn)IComponent接口)。注意這里的建議,也就是說(shuō)不是強(qiáng)制性的,你完全可以定義一個(gè)People類,讓其實(shí)現(xiàn)IComponent接口,這合法!結(jié)果就是,從工具欄中拖放一個(gè)People到窗體設(shè)計(jì)器中,它會(huì)自動(dòng)幫你實(shí)例化了一個(gè)People對(duì)象實(shí)例,并且你也能通過(guò)屬性窗體編輯它的屬性值(這些后臺(tái)都能自動(dòng)生成對(duì)應(yīng)代碼)。另外,經(jīng)發(fā)現(xiàn),具備某一些功能的類型,雖然跟界面無(wú)交互,但是它還是支持可視化設(shè)計(jì),比如BackgroundWorker組件,拖一個(gè)BackgroundWorker到窗體設(shè)計(jì)器中去,設(shè)計(jì)器會(huì)自動(dòng)幫你實(shí)例化一個(gè)Backgroundworker對(duì)象(生成對(duì)應(yīng)代碼),然后你可以通過(guò)屬性窗體編輯它的屬性值(生成對(duì)應(yīng)代碼),這跟你自己手動(dòng)new BackgroundWorker沒(méi)有區(qū)別,你還是可以在其他地方一樣使用該backgroundworke對(duì)象,至少你目前看起來(lái)沒(méi)區(qū)別。
為了更好的說(shuō)明通過(guò)窗體設(shè)計(jì)器設(shè)計(jì)出來(lái)的對(duì)象,跟我們手動(dòng)編寫代碼搞出來(lái)的對(duì)象有什么相同和不同點(diǎn),我們先來(lái)分析一下Form1.Designer.cs中的代碼:
我們注意到,我們?cè)谠O(shè)計(jì)器中的每一步操作,對(duì)應(yīng)生成的代碼都在InitializeComponent()方法中,它像是word錄制宏的功能,你在word中的每一個(gè)操作,都可以生成對(duì)應(yīng)的VBA代碼,也就是說(shuō),窗體設(shè)計(jì)器從實(shí)例化對(duì)象,到編輯屬性,再到注冊(cè)事件等等等,都有代碼幫我們記錄下這些操作。我們?cè)倏匆幌聦?shí)例化對(duì)象的代碼:
?View Code沒(méi)錯(cuò),任何一個(gè)實(shí)例化出來(lái)的對(duì)象,都給它傳遞了this.components容器,我們?cè)倏碝yComponent的構(gòu)造方法是這樣的:
?View Code也就是說(shuō),對(duì)象實(shí)例化的時(shí)候,都將該對(duì)象放進(jìn)了一個(gè)components的容器,這個(gè)容器專門用來(lái)存放由窗體設(shè)計(jì)器實(shí)例化出來(lái)的對(duì)象(控件除外)。這就像一個(gè)大的容器,專門來(lái)存放這些小個(gè)體。接下來(lái)我們?cè)賮?lái)看一下Form1.Designer.cs中的dispose方法:
?View Code我們可以發(fā)現(xiàn),在Form1對(duì)象Dispose的時(shí)候,它將components中的所有個(gè)體都Dispose掉了。到此,我們可以總結(jié)出來(lái)一條:由窗體設(shè)計(jì)器設(shè)計(jì)出來(lái)的對(duì)象由父窗體(父控件)的InitializeComponents方法統(tǒng)一初始化,由父窗體(父控件)的Dispose()方法統(tǒng)一釋放資源。我們來(lái)看一張F(tuán)orm1運(yùn)行結(jié)構(gòu)圖:
圖(更新)1
由此可以看出,由窗體設(shè)計(jì)器設(shè)計(jì)出來(lái)的對(duì)象,它們的生命周期以及存放結(jié)構(gòu)都比較有規(guī)律,這個(gè)就是窗體設(shè)計(jì)器設(shè)計(jì)出來(lái)對(duì)象的好處。
我們?cè)谕绑w設(shè)計(jì)器中拖放組件時(shí),就是往Form1類型中添加新的成員對(duì)象,跟我們定義一個(gè)類型,向里面添加成員變量一個(gè)意思,只是前者更直觀,添加的每一個(gè)成員對(duì)象,在UI設(shè)計(jì)器中都能看見(jiàn)與它對(duì)應(yīng)的一個(gè)對(duì)象實(shí)例,只要我們改變了這個(gè)對(duì)象實(shí)例的屬性,就能馬上看見(jiàn)設(shè)計(jì)器中的對(duì)象實(shí)例效果,緊接著后臺(tái)生成代碼;而后者就沒(méi)有這么直觀了,只能手寫代碼,而且還看不見(jiàn)效果。
圖(更新)2
如上圖,窗體設(shè)計(jì)器中某一個(gè)對(duì)象實(shí)例屬性更新之后,馬上就能在設(shè)計(jì)器中看見(jiàn)效果(因?yàn)樗菍?shí)實(shí)在在存在于堆中的對(duì)象),接著InitializeComponents中的代碼就會(huì)更新,注意,窗體設(shè)計(jì)器中的myComponent1對(duì)象實(shí)例跟.cs代碼中的myComponent1變量不是一個(gè)東西,他們只有一種映射關(guān)系。我們最終要的是.cs中的代碼文件,而不是我們看見(jiàn)的窗體設(shè)計(jì)器中的圖像,后者只是起到一個(gè)可視化的效果,最終一文不值。這個(gè)就像photoshop作圖一樣,最終保存到硬盤的圖片文件才是最重要的,作圖過(guò)程中作圖區(qū)域顯示的東西沒(méi)有價(jià)值。窗體設(shè)計(jì)器隱藏得越多,我們知道得越少。
作者:周見(jiàn)智?
出處:http://www.cnblogs.com/xiaozhi_5638/?
本文版權(quán)歸作者和博客園共有,歡迎轉(zhuǎn)載,但未經(jīng)作者同意必須保留此段聲明,且在文章頁(yè)面明顯位置給出原文連接,否則保留追究法律責(zé)任的權(quán)利。
本文轉(zhuǎn)自周見(jiàn)智博客博客園博客,原文鏈接:http://www.cnblogs.com/xiaozhi_5638/p/3463774.html,如需轉(zhuǎn)載請(qǐng)自行聯(lián)系原作者
總結(jié)
以上是生活随笔為你收集整理的.Net开发笔记(十九) 创建一个可以可视化设计的对象的全部?jī)?nèi)容,希望文章能夠幫你解決所遇到的問(wèn)題。
- 上一篇: 邮件:事务失败。 服务器响应为:DT:S
- 下一篇: ArcGIS Engine 编辑介绍