WinForm控件開發(fā)總結(jié)_第1頁
WinForm控件開發(fā)總結(jié)_第2頁
WinForm控件開發(fā)總結(jié)_第3頁
WinForm控件開發(fā)總結(jié)_第4頁
WinForm控件開發(fā)總結(jié)_第5頁
已閱讀5頁,還剩48頁未讀, 繼續(xù)免費閱讀

下載本文檔

版權(quán)說明:本文檔由用戶提供并上傳,收益歸屬內(nèi)容提供方,若內(nèi)容存在侵權(quán),請進行舉報或認領(lǐng)

文檔簡介

1、WinForm控件開發(fā)總結(jié)(一)開篇我本人不是專業(yè)的控件開發(fā)人員,只是在平常的工作中,需要自己開發(fā)一些控件。在自己開發(fā)WinForm控件的時候,沒有太多可以借鑒的資料,只能盯著MSDN使勁看,還好總算有些收獲?,F(xiàn)在我會把這些經(jīng)驗陸陸續(xù)續(xù)的總結(jié)出來,寫成一系列方章,希望對看到的朋友有所幫助。今天我來開個頭。其實開發(fā)WinForm控件并不是很復雜,.NET為我們提供了豐富的底層支持。如果你有MFC或者API圖形界面的開發(fā)經(jīng)驗,那么學會WinForm控件可能只需要很短的時間就夠了。自己開發(fā)的WinForm控件通常有三種類型:復合控件(CompositeControls),擴展控件(ExtendedC

2、ontrols),自定義控件(CustomControls)。復合控件:將現(xiàn)有的各種控件組合起來,形成一個新的控件,將集中控件的功能集中起來。擴展控件:在現(xiàn)有控件的控件的基礎上派生出一個新的控件,為原有控件增加新的功能或者修改原有控件的控能。自定義控件:直接從System.Windows.Forms.Control類派生出來。Control類提供控件所需要的所有基本功能,包括鍵盤和鼠標的事件處理。自定義控件是最靈活最強大的方法,但是對開發(fā)者的要求也比較高,你必須為Control類的OnPaint事件寫代碼,你也可以重寫Control類的WndProc方法,處理更底層的Windows消息,所以你

3、應該了解GDI+和WindowsAPI。本系列文章主要介紹自定義控件的開發(fā)方法??丶?可視化的)的基本特征:可視化??梢耘c用戶進行交互,比如通過鍵盤和鼠標。暴露出一組屬性和方法供開發(fā)人員使用。暴露出一組事件供開發(fā)人員使用??丶傩缘目沙志没???砂l(fā)布和可重用。這些特征是我自己總結(jié)出來,不一定準確,或者還有遺漏,但是基本上概括了控件的主要方面。接下來我們做一個簡單的控件來增強一下感性認識。首先啟動VS2005創(chuàng)建一個ClassLibrary工程,命名為CustomControlSample,VS會自動為我們創(chuàng)建一個solution與這個工程同名,然后刪掉自動生成的Class1.cs文件,最后在So

4、lutionexplorer里右鍵點擊CustomControlSample工程選擇Add-Classes添加一個新類,將文件的名稱命名為FirstControl。下邊是代碼:usingSystem;usingSystem.Collections.Generic;usingSystem.Text;usingSystem.Windows.Forms;usingSystem.ComponentModel;usingSystem.Drawing;namespaceCustomControlSample日IpublicclassFirstControl:ControlIIpublicFirstCont

5、rol()申III/ContentAlignmentisanenumerationdefinedintheSystem.DrawingI/namespacethatspecifiesthealignmentofcontentonadrawingI/surface.IprivateContentAlignmentalignmentValue=ContentAlignment.MiddleLeft;ICategory(Alignment),Description(Specifiesthealignmentoftext.)publicContentAlignmentTextAlignmentgetr

6、eturnalignmentValue;setalignmentValue=value;/TheInvalidatemethodinvokestheOnPaintmethoddescribed/instep3.Invalidate。;protectedoverridevoidOnPaint(PaintEventArgse)base.OnPaint(e);StringFormatstyle=newStringFormat();style.Alignment=StringAlignment.Near;switch(alignmentValue)caseContentAlignment.Middle

7、Left:style.Alignment=StringAlignment.Near;break;caseContentAlignment.MiddleRight:style.Alignment=StringAlignment.Far;break;caseContentAlignment.MiddleCenter:style.Alignment=StringAlignment.Center;break;/CalltheDrawStringmethodoftheSystem.Drawingclasstowrite/text.TextandClientRectanglearepropertiesin

8、heritedfrom/Control.e.Graphics.DrawString(Text,Font,newSolidBrush(ForeColor),ClientRectangle,style);在上一篇文章里我們創(chuàng)建了一個簡單的控件FirstControl,現(xiàn)在我來介紹一下怎么使用和調(diào)試自己的控件。我希望將過程寫的盡可能的詳細,讓想學習控件開發(fā)的朋友容易上手,高手們見諒。在同一個solution里添加一個WindowsApplication工程(在SolutionExplorer里右鍵點擊CustomControlSamplesolution選擇Add-Newroect),命名為Test

9、ControlVS會為你自動生成一個Form,文件名為Form1.cs。在SolutionExplorer里雙擊Form1.cs文件進入到Form設計界面?,F(xiàn)在我們將FirstControl控件添加到工具箱(ToolBox)里,在Toolbox上右鍵點擊,在彈出的菜單中選擇Choosetems,在出現(xiàn)的ChooseToolboxItems對話框中點擊rose按鈕,在Open對話框中選擇我們的控件工程生成的dll(我的dll在F:ProgramsC#CustomControlSampleCustomControlSamplebinDebug目錄下,你可以根據(jù)實際情況去找)。完成這一步,在Tool

10、box就會出現(xiàn)我們設計的控件,圖標是一個藍色的齒輪(默認的都是這個,當然你也可以修改,后邊的文章我會介紹),名稱是FirstControl?,F(xiàn)在我們在Toolbox中選中FirstControl,在form設計器上左鍵點擊,或者按住鼠標拖放。我們制作的控件出現(xiàn)在了Form設計器上,在Form設計器上選中這個控件,然后在屬性瀏覽器中將Text屬性設為HelloWorId,現(xiàn)在我們的控件上的文字變成了HelloWorld。接下來我們要運行測試的工程,看看實際的效果。在運行之前,將測試工程設為啟動工程,具體做法是,在solutionexplorer中右鍵點擊TestControl工程,選擇Setas

11、StartupProect”點擊工具欄里的運行按鈕,或者按鍵盤的F5功能鍵。實際效果如下圖所示:WinForm控件開發(fā)總結(jié)(三)認識WinForm控件常用的Attribute在前面的文章里我們制作了一個非常簡單的控件。現(xiàn)在我們回過頭來看看這些代碼透露出什么信息。這個類是直接從Control類派生出來的,自定義控件都是直接從Control類派生出來的這個類定義了一個屬性TextAlignment,用來控制文本在控件中顯示的位置:Category(Alignment),Description(Specifiesthealignmentoftext.)publicContentAlignmentTe

12、xtAlignment日IgetIreturnalignmentValue;:IalignmentValue=value;_invokestheOnPaintmethoddescribedI/instep3.IInvalidate。;在這個屬性之上有兩個,這兩個描述了控件在設計時所表現(xiàn)出來的特征。我們來看看在控件設計中有哪些主要用到的設計時。BrowsableAttribute:描述是否一個屬性或事件應該被顯示在屬性瀏覽器里。CategoryAttribute:描述一個屬性或事件的類別,當使用類別的時候,屬性瀏覽器按類別將屬性分組。DescriptionAttribute:當用戶在屬性瀏覽器里

13、選擇屬性的時候,description里指定的文本會顯示在屬性瀏覽器的下邊,向用戶顯示屬性的功能。BindableAttribute:描述是否一個屬性傾向于被綁定。DefaultPropertyAttribute:為組件指定一個默認的屬性,當用戶在Form設計器上選擇一個控件的時候,默認屬性會在屬性瀏覽器里被選中。DefauItValueAttribute:為一個簡單類型的屬性設置一個默認值。EditorAttribute:為屬性指定一個特殊的編輯器。LocalizableAttribute:指示一個屬性是否能被本地化,任何有這個Attribute的屬性將會被持久化到資源文件里。Designe

14、rSerializationVisibilityAttribute:指示一個屬性是否或者如何持久化到代碼里。TypeConverterAttribute:為屬性指定一個類型轉(zhuǎn)換器,類型轉(zhuǎn)換器能將屬性的值轉(zhuǎn)化成其它的數(shù)據(jù)類型。DefaultEventAttribute:為組件指定一個默認的事件,當用戶在form設計其中選擇一個控件的時候,在屬性瀏覽器中這個事件被選中。這些設計時的Attribute時很重要的,如果使用的好,將會對用戶的使用帶來很大的便利。這一章我主要介紹了設計時的Attribute,接下來的文章我將通過代碼來介紹這些Attribute。WinForm控件開發(fā)總結(jié)(四)控件屬性的串

15、行化前一篇文章介紹了常用的設計時Attribute。其中BrowsableAttribute,CategoryAttribute,DescriptionAttribute,DefaultPropertyAttribute,DefaultEventAttribute都是比較簡單的,也是可有可無,但是為了提供更好的用戶體驗這些Attribute最好不要省掉,如果你對這些Attribute還不熟悉,可以參考我前一篇文章的描述或者查看MSDN,這里我就不在贅述了。下來我們主要介紹一下DesignerSerializationVisibilityAttribute和TypeConverterAttrib

16、ute。DesignerSerializationVisibilityAttribute的功能是指示一個屬性是否串行化和如何串行化,它的值是一個枚舉,一共有三種類型Content,Hidden.Visible。Content指示代碼生成器為對象包含的內(nèi)容生成代碼,而不是為對象本身,Hidden指示代碼生成器不為對象生成代碼,visible指示代碼生成器為對象生成代碼。假如你的控件有一個集合屬性,又想在設計時自動將集合屬性的內(nèi)容生成代碼,那么就使用這個Attribute,并將值設為DesignerSerializationVisibility.Content。TypeConverterAttri

17、bute的作用就更大一些,也稍微復雜一些。TypeConverterAttribute主要的目的是為屬性指定一個類型轉(zhuǎn)換器,這個轉(zhuǎn)化器可以將屬性的值轉(zhuǎn)換城其它的類型。.NET框架已經(jīng)為大部分常用的類型都提供了類型轉(zhuǎn)換器,比如Color就有ColorConverter.枚舉類型就有EnumConverter,等等,所以一般情況下你沒有必要寫類型轉(zhuǎn)換器,如果你的屬性的特殊的類型或者自定義的類型那么就必須要寫了。類型轉(zhuǎn)換器都是從System.ComponentModel.TypeConverter派生出來的,你需要重寫其中的一些方法來達到轉(zhuǎn)換的目的,在我們開發(fā)的過程中,其實只關(guān)心屬性的值如何轉(zhuǎn)換成字

18、符串(因為屬性的值需要在屬性瀏覽器里顯示出來,屬性瀏覽器里顯示的都是字符串)和源代碼(需要自動為屬性的值生成源代碼以實現(xiàn)持久化),當然反過來,也要將字符串和源代碼轉(zhuǎn)換成屬性的值。另外使用TypeConverter也可以實現(xiàn)子屬性,讓屬性的子屬性也顯示在屬性瀏覽器里,并且可以折疊。接下來我就寫一個簡單的控件來演示一下這個控件。代碼如下:usingSystem;usingSystem.Collections.Generic;usingSystem.Text;usingSystem.Windows.Forms;usingSystem.Drawing;usingSystem.ComponentMode

19、l;usingSystem.Collections;namespaceCustomControlSample日IpublicclassMyListControl:System.Windows.Forms.ControlprivateList_list=newList();IpublicMyListControl()Browsable(true)publicListvInt32Itemgetreturn_list;setlist=value;protectedoverridevoidOnPaint(PaintEventArgse)base.OnPaint(e);Graphicsg=e.Graph

20、ics;繪制控件的邊框g.DrawRectangle(Pens.Black,newRectangle(Point.Empty,newSize(Size.Width-1,Size.Height-1);for(Int32i=0;ic:=Lti-:iTl12,34LuclzeilF:eJ_S6田M:=ltn富3爲3+6oMinimuiTiSireo,oModifiqteFrivata3Fidding0,0,U,0RightToLettWoi!Size220f18CT:.b工口1TabStopTrueTagISK-jtpLitCoiitrollUzsTtfaitCurEOFFalseVisibleTr

21、ueehj_Ini32V:=J_ne1PropertiTXPropertiTX添加完以后,關(guān)閉CollectionEditor?,F(xiàn)在我們看看Form設計器為我們生成了什么代碼。對于用戶在Form設計器中設計的內(nèi)容,設計器的代碼生成器會將代碼生成到窗口類的InitializeComponent()方法中,對于vs2005來說,這個方法位于*.Designer.cs文件中,在我當前的工程中位于Forml.Designer.cs文件中。在solution瀏覽器中雙擊打開這個文件,看看Form設計器為我們生成了什么代碼:/myListControl1/this.myListControl1.BackC

22、olor=System.Drawing.SystemColors.ActiveCaptionText;this.myListControl1.Item=(System.Collections.Generic.List)(resources.GetObject(myListControl1.Item);this.myListControl1.Location=newSystem.Drawing.Point(12,34);this.myListControl1.Name=myListControl1;this.myListControll.Size=newSystem.Drawing.Size(2

23、20,180);this.myListControll.Tablndex=1;this.myListControl1.Text=myListControl1;設計器將Item的內(nèi)容串行化到了資源文件里?,F(xiàn)在我們修改控件的代碼,讓設計器將Item的內(nèi)容串行化到源代碼里。我們?yōu)镮tem屬性添加DesignerSerializationVisibilityAttribute,代碼片斷如下:Browsable(true)DesignerSerializationVisibilityAttribute(DesignerSerializationVisibility.Content)publicListI

24、temgetreturn_list;set_list=value;編輯完以后,Build控件工程,回到測試工程里,將Item屬性里的值,刪掉重新添加,添加完以后,我們再來看看設計器生成的代碼:/myL/this.myListControll.BackColor=System.Drawing.SystemColors.ActiveCaptionText;this.myListControll.Item.Add(l);this.myListControll.Item.Add(2);this.myListControll.Item.Add(3);this.myListControll.Item.Ad

25、d(6);this.myListControll.Item.Add(8);this.myListControll.Item.Add(9);this.myListControll.Location=newSystem.Drawing.Point(12,34);this.myListControll.Name=myListControll;this.myListControll.Size=newSystem.Drawing.Size(220,180);this.myListControl1.TabIndex=1;this.myListControl1.Text=myListControl1;現(xiàn)在設

26、計器將Item的內(nèi)容串行化到源代碼里了。時間有限,今天就寫到這里,下一篇文章我來介紹TypeConverterAttribute。WinForm控件開發(fā)總結(jié)(五)為控件的復雜屬性提供類型轉(zhuǎn)換器上一篇文章我已經(jīng)介紹了TypeConverterAttribute元數(shù)據(jù)的作用,本文將通過代碼向你展示具體的實現(xiàn)。在這個例子中,我要給控件添加一個復雜的屬性,這個屬性對這個控件沒有什么功用,純粹是為了演示,有些牽強附會了。現(xiàn)在在前一篇文章中的創(chuàng)建的控件代碼中添加一個Scope屬性:Browsable(true)publicScopeScope日Igetreturn_scope;Set_scope=valu

27、e;這個屬性的類型是Scope類,代碼如下:publicclassScope日privateInt32_min;privateInt32_max;IIpublicScope()申IpublicScope(Int32min,Int32max)_min=min;IBrowsable(true)IpublicInt32MinIget申return_min;setmin=value;Browsable(true)publicInt32Maxgetreturn_max;set_max=value;添加完屬性后,build控件工程,然后在測試的工程里選中添加的控件,然后在屬性瀏覽器里觀察它的屬性,發(fā)現(xiàn)Sc

28、ope屬性是灰的,不能編輯。前一篇文章提到了,在屬性瀏覽器里可以編輯的屬性都是有類型轉(zhuǎn)換器的,而.NET框架為基本的類型和常用的類型都提供了默認的類型轉(zhuǎn)換器。接下來我們?yōu)镾cope類添加一個類型轉(zhuǎn)換器,以便這個屬性能夠被編輯,而且也可以在源代碼文件里自動生成相應的代碼。下面是類型轉(zhuǎn)換器的代碼:publicclassScopeConverter:TypeConverter日IpublicoverrideboolCanConvertFrom(ITypeDescriptorContextcontext,TypesourceType)Iif(sourceType=typeof(String)retur

29、ntrue;IIreturnbase.CanConvertFrom(context,sourceType);IIpublicoverrideboolCanConvertTo(ITypeDescriptorContextcontext,TypedestinationType)Iif(destinationType=typeof(String)returntrue;IIif(destinationType=typeof(InstanceDescriptor)returntrue;IIreturnbase.CanConvertTo(context,destinationType);IIpublico

30、verrideobjectConvertTo(ITypeDescriptorContextcontext,System.Globalization.CultureInfoculture,objectvalue,TypedestinationType)IStringresult=;Iif(destinationType=typeof(String)Scopescope=(Scope)value;result=scope.Min.ToString()+,+scope.Max.ToString();returnresult;if(destinationType=typeof(InstanceDesc

31、riptor)申Constructorinfoci=typeof(Scope).GetConstructor(newTypetypeof(Int32),typeof(Int32);Scopescope=(Scope)value;returnnewInstanceDescriptor(ci,newobjectscope.Min,scope.Max);returnbase.ConvertTo(context,culture,value,destinationType);publicoverrideobjectConvertFrom(ITypeDescriptorContextcontext,Sys

32、tem.Globalization.Cultureinfoculture,objectvalue)if(valueisstring)Stringv=(String)value).Split(T);if(v.GetLength(O)!=2)thrownewArgumentException(Invalidparameterformat);Scopecsf=newScope();csf.Min=Convert.Toint32(v0);csf.Max=Convert.ToInt32(vl);Ireturncsf;Ireturnbase.ConvertFrom(context,culture,valu

33、e);現(xiàn)在我們?yōu)轭愋吞峁╊愋娃D(zhuǎn)換器,我們在類型前面添加一個TypeConverterAttribute,如下:TypeConverter(typeof(ScopeConverter)publicclassScope添加完以后build工程,然后切換到測試工程,選中控件,在屬性瀏覽器里查看屬性,現(xiàn)在的Scope屬性可以編輯了,如下圖所示:+PaddingNo10,23G22(3r180RightTd匸eftSeepsSize我們修改默認的值,然后看看Form設計器為我們生成了什么代碼:this.myListControll.BackColor=System.Drawing.SystemColor

34、s.ActiveCaptionText;this.myListControll.Item.Add(l);this.myListControll.Item.Add(2);this.myListControll.Item.Add(3);this.myListControll.Item.Add(6);this.myListControll.Item.Add(8);this.myListControll.Item.Add(9);this.myListControll.Location=newSystem.Drawing.Point(12,34);this.myListControll.Name=myL

35、istControll;this.myListControll.Scope=newCustomControlSample.Scope(10,200);this.myListControll.Size=newSystem.Drawing.Size(220,180);this.myListControl1.TabIndex=1;this.myListControl1.Text=myListControl1;關(guān)鍵是這一行this.myListControll.Scope=newCustomControlSample.Scope(10,200),Scope類的類型轉(zhuǎn)換器為屬性提供了實例化的代碼。Win

36、Form控件開發(fā)總結(jié)(六)控件屬性類型轉(zhuǎn)換器代碼詳解在上一篇文章,我為控件添加一個一個復雜屬性,并且為這個屬性的類型的編寫了一個類型轉(zhuǎn)換器,現(xiàn)在我們來看看這個類型轉(zhuǎn)換器的代碼,并解釋一下這些代碼的意義。要實現(xiàn)一個類型轉(zhuǎn)換器,我們必須要重寫(override)四個方法:CanConvertFrom()根據(jù)類型參數(shù)進行測試,判斷是否能從這個類型轉(zhuǎn)換成當前類型,在本例中我們只提供轉(zhuǎn)換string和InstanceDescriptor類型的能力。CanConvertTo()根據(jù)類型參數(shù)進行測試,判斷是否能從當前類型轉(zhuǎn)換成指定的ConvertTo()將參數(shù)value的值轉(zhuǎn)換為指定的類型。ConvertF

37、rom()串換參數(shù)value,并返回但書類型的一個對象。publicoverrideobjectConvertTo(ITypeDescriptorContextcontext,System.Globalization.CultureInfoculture,objectvalue,TypedestinationType)Stringresult=;if(destinationType=typeof(String)Scopescope=(Scope)value;result=scope.Min.ToString()+,+scope.Max.ToString();returnresult;if(de

38、stinationType=typeof(InstanceDescriptor)申Constructorlnfoci=typeof(Scope).GetConstructor(newTypetypeof(Int32),typeof(Int32);IScopescope=(Scope)value;申returnnewInstanceDescriptor(ci,newobjectscope.Min,scope.Max);Ireturnbase.ConvertTo(context,culture,value,destinationType);上面是ConvertTo的實現(xiàn),如果轉(zhuǎn)換的目標類型是str

39、ing,我將Scope的兩個屬性轉(zhuǎn)換成string類型,并且用一個“,”連接起來,這就是我們在屬性瀏覽器里看到的表現(xiàn)形式,如圖:Faddirigo.o.aoRightTuLettNo.Scope10,206mt-r*220,160如果轉(zhuǎn)換的目標類型是實例描述器(InstanceDescriptor,它負責生成實例化的代碼),我們需要構(gòu)造一個實例描述器,構(gòu)造實例描述器的時候,我們要利用反射機制獲得Scope類的構(gòu)造器信息,并在new的時候傳入Scope實例的兩個屬性值。實例描述器會為我們生成這樣的代碼:this.myListControll.Scope=newCustomControlSampl

40、e.Scope(10,200);在最后不要忘記調(diào)用base.ConvertTo(context,culture,value,destinationType),你不需要處理的轉(zhuǎn)換類型,交給基類去做好了。0publicoverrideobjectConvertFrom(ITypeDescriptorContextcontext,System.Globalization.CultureInfoculture,objectvalue)日Iif(valueisstring)IStringv=(String)value).Split(,);Iif(v.GetLength(O)!=2)申IthrownewA

41、rgumentException(Invalidparameterformat);IIScopecsf=newScope();Icsf.Min=Convert.ToInt32(v0);Icsf.Max=Convert.ToInt32(v1);Ireturncsf;Ireturnbase.ConvertFrom(context,culture,value);上面是ConvertFrom的代碼,由于系統(tǒng)能夠直接將實例描述器轉(zhuǎn)換為Scope類型,所以我們就沒有必要再寫代碼,我們只需要關(guān)注如何將String(在屬性瀏覽出現(xiàn)的屬性值的表達)類型的值轉(zhuǎn)換為Scope類型。沒有很復雜的轉(zhuǎn)換,只是將這個字符串

42、以“,分拆開,并串換為Int32類型,然后new個Scope類的實例,將分拆后轉(zhuǎn)換的兩個整型值賦給Scope的實例,然后返回實例。在這段代碼里,我們要判斷一下用戶設定的屬性值是否有效。比如,如果用戶在Scope屬性那里輸入了“10200”,由于沒有輸入“,”,我們無法將屬性的值分拆為兩個字符串,也就無法進行下面的轉(zhuǎn)換,所以,我們要拋出一個異常,通知用戶重新輸入。(請您對文章做出評價)WinForm控件開發(fā)總結(jié)(七)為復雜屬性的子屬性提供編輯功能前面的幾篇文章中,我們給控件添加一個復雜的類型Scope,并且給它的類型提供的一個類型轉(zhuǎn)換器,現(xiàn)在我們可以在屬性瀏覽器中編輯它的值,并且它的值也被串行化

43、的源代碼里了。但是你有沒有發(fā)現(xiàn),在屬性瀏覽器里編輯這個屬性的值還是不太方便。因為屬性只是“1,0200這種形式的,所以,你必須按照這種格式來修改,一旦格式錯誤就會引發(fā)異常,比如輸入一個“0200”。我們期望這個屬性的每一子屬性都能夠被獨立的編輯就好了,這并非不能實現(xiàn),而且實現(xiàn)還很簡單。為了在屬性瀏覽器里能夠獨立的編輯子屬性,我們還要重寫兩個方法:GetPropertiesSupported()和GetProperties();下面是ScopeConverter的完整代碼:publicclassScopeConverter:TypeConverter日IpublicoverrideboolCan

44、ConvertFrom(ITypeDescriptorContextcontext,TypesourceType)申Iif(sourceType=typeof(String)returntrue;IIreturnbase.CanConvertFrom(context,sourceType);IIpublicoverrideboolCanConvertTo(ITypeDescriptorContextcontext,TypedestinationType)if(destinationType=typeof(String)returntrue;0if(destinationType=typeof(

45、InstanceDescriptor)returntrue;returnbase.CanConvertTo(context,destinationType);publicoverrideobjectConvertTo(ITypeDescriptorContextcontext,System.Globalization.CultureInfoculture,objectvalue,TypedestinationType)Stringresult=;if(destinationType=typeof(String)Scopescope=(Scope)value;result=scope.Min.T

46、oString()+,+scope.Max.ToString();returnresult;if(destinationType=typeof(InstanceDescriptor)申ConstructorInfoci=typeof(Scope).GetConstructor(newTypetypeof(Int32),typeof(Int32);Scopescope=(Scope)value;申returnnewInstanceDescriptor(ci,newobjectscope.Min,scope.Max);returnbase.ConvertTo(context,culture,val

47、ue,destinationType);publicoverrideobjectConvertFrom(ITypeDescriptorContextcontext,System.Globalization.CultureInfoculture,objectvalue)if(valueisstring)Stringv=(String)value).Split(,);if(v.GetLength(O)!=2)thrownewArgumentException(Invalidparameterformat);Scopecsf=newScope();csf.Min=Convert.Tolnt32(v0

48、);csf.Max=Convert.Tolnt32(v1);returncsf;returnbase.ConvertFrom(context,culture,value);publicoverrideboolGetPropertiesSupported(ITypeDescriptorContextcontext)returntrue;publicoverridePropertyDescriptorCollectionGetProperties(ITypeDescriptorContextcontext,objectvalue,Attributeattributes)0returnTypeDes

49、criptor.GetProperties(typeof(Scope),attributes);在GetProperties方法里,我用TypeDescriptor獲得了Scope類的所有的屬性描述器并返回。如果你對TypeDescriptor還不熟悉的話,可以參考MSDN。重寫這兩個方法并編譯以后,在測試工程里查看控件的屬性,你可以看到Scope是如下的形式:日:Scope20,30M當:14)WinWinForm控件開發(fā)總結(jié)(八)為屬性提供彈出式編輯對話框前幾篇文章我們一直在討論如何更方便的編輯復雜類型的屬性,在這個過程中我介紹了類型轉(zhuǎn)換器以及如何制作自己的類型轉(zhuǎn)換器來實現(xiàn)屬性值的串行化和

50、實現(xiàn)子屬性的編輯。對于Scope這種級別的復雜屬性,一個類型轉(zhuǎn)換器就已經(jīng)足夠了,但是對于更為復雜的屬性,單單使用類型轉(zhuǎn)換器已經(jīng)不足以應付了,比如我們常用的Font屬性。在這種情況下,我們就需要提供更為復雜的編輯方式,比如屬性編輯對話框,你還記得Font對話框嗎?現(xiàn)在我們就來看看如何實現(xiàn)更復雜的屬性編輯。復雜的屬性編輯器分為兩種類型,一種是彈出式模態(tài)對話框?qū)傩跃庉嬈?,一種式下拉式屬性編輯器。如果你還沒有感性的認識的話,可以觀察一下TextBox控件的屬性,F(xiàn)ont屬性的編輯器是模態(tài)對話框?qū)傩跃庉嬈鳎珼ock屬性的編輯器是下拉式屬性編輯器。接下來我們來制作一個模態(tài)對話框編輯器,雖然Scope屬性并

51、不復雜,但是為了演示的方便,我們還是用它來做例子。首先我們要做一個用來編輯屬性的對話框,在對話框的構(gòu)造函數(shù)里傳入要編輯的屬性的值。在對話框類里,聲明一個Scope類型的私有變量_scope用以保存?zhèn)魅牒途庉嫼蟮闹?。還要增加一個Scope屬性,以便外部環(huán)境能夠獲取編輯后的結(jié)果。對話框的外觀如下:0在這個對話框里,我們要把0K按鈕的DialogResult屬性設為OK(當點擊0K按鈕時,模態(tài)對話框關(guān)閉,并返回DialogResult.OK),將Cancel按鈕的DialogResult屬性設為Cancel(當點擊OK按鈕時,模態(tài)對話框關(guān)閉,并返回DialogResult.OK)。另外我們要對用戶輸

52、入的值做驗證,以保證Scope的min和max值都是Int32類型。下邊是對話框的代碼:usingSystem;usingSystem.Collections.Generic;usingSystem.ComponentModel;usingSystem.Data;usingSystem.Drawing;usingSystem.Text;usingSystem.Windows.Forms;namespaceCustomControlSample日IpublicpartialclassScopeEditorDialog:Form申privateScope_scope=null;IIpublicSc

53、opeEditorDialog(Scopescope)IInitializeComponent();scope=scope;textBox1.Text=_scope.Min.ToString();textBox2.Text=_scope.Max.ToString();privatevoidbutton1_Click(objectsender,EventArgse)_scope.Min=Convert.ToInt32(textBox1.Text);_scope.Max=Convert.ToInt32(textBox2.Text);privatevoidtextBox1_Validating(ob

54、jectsender,CancelEventArgse)tryInt32.Parse(textBox1.Text);catch(FormatException)e.Cancel=true;MessageBox.Show(無效的值,驗證錯誤,MessageBoxButtons.OK,MessageBoxIcon.Error);privatevoidtextBox2_Validating(objectsender,CancelEventArgse)申Itry申IInt32.Parse(textBox2.Text);Icatch(FormatException)Ie.Cancel=true;IMes

55、sageBox.Show(無效的值,驗證錯誤,MessageBoxButtons.OK,MessageBoxIcon.Error);IpublicScopeScopeIgetreturn_scope;set_scope=value;每一個屬性的編輯器都是直接或者間接的派生于UITypeEditor。開發(fā)環(huán)境從來也不會直接調(diào)用我們編寫的模態(tài)對話框來編輯屬性,而是調(diào)用UITypeEditor的某些虛方法,所以我們還必須提供一個派生于UITypeEditor的類來與開發(fā)環(huán)境通信。下邊的代碼實現(xiàn)了Scope的編輯器:usingSystem;usingSystem.ComponentModel;usin

56、gSystem.Drawing.Design;usingSystem.Windows.Forms.Design;usingSystem.Windows.Forms;namespaceCustomControlSample日IpublicclassScopeEditor:UITypeEditorIpublicoverrideUITypeEditorEditStyleGetEditStyle(ITypeDescriptorContextcontext)Iif(context!=null&context.Instance!=null)IreturnUITypeEditorEditStyle.Moda

57、l;IIreturnbase.GetEditStyle(context);IIpublicoverrideobjectEditValue(ITypeDescriptorContextcontext,IServiceProviderprovider,objectvalue)IIWindowsFormsEditorServiceeditorService=null;if(context!=null&context.Instance!=null&provider!=null)IeditorService=(IWindowsFormsEditorService)provider.GetService(

58、typeof(IWindowsFormsEditorService);if(editorService!=null)MyListControlcontrol=(MyListControl)context.Instance;ScopeEditorDialogdlg=newScopeEditorDialog(control.Scope);if(dlg.ShowDialog()=DialogResult.OK)value=dlg.Scope;returnvalue;returnvalue;在這個類里,我們重寫了兩個方法,一個是GetEditStyle,在這個方法里,我們通知開發(fā)環(huán)境,屬性的編輯器是一

59、個模態(tài)對話框。另一個方法是EditValue,這是最核心的方法,在這個方法里,我們通過上下文環(huán)境獲得了正在編輯的控件的實例,并將實例的Scope屬性傳遞給屬性編輯對話框,顯示對話框供用戶編輯屬性的值,用戶編輯完屬性的值,并關(guān)閉對話框,這時,我們從對話框里獲取編輯后的結(jié)果反會給開發(fā)環(huán)境。編寫完Editor,我們就要將它應用到MyListControl的Scope屬性上,現(xiàn)在的Scope屬性定義如下:Browsable(true)Editor(typeof(ScopeEditor),typeof(UITypeEditor)publicScopeScopegetreturn_scope;set_sc

60、ope=value;我們在Scope屬性前加上了Editor(typeof(ScopeEditor),typeof(UITypeEditor)元數(shù)據(jù)。Build工程,查看實際的效果。在測試工程的窗體上,選中控件,觀察Scope屬性,當我們單擊Scope屬性的值時,在屬性值的后邊出現(xiàn)了一個按鈕,如圖:LightToLeftFo-1fl期Scope:flSizeFIT-122d,ISO0當我們點擊這個按鈕后,彈出了屬性編輯的對話框,如圖:ElMinimuniSi工旨40NodifieraFtirateEETaading0.ma0EightT&Left吃0Scl:-pt!12J200E220,80T

溫馨提示

  • 1. 本站所有資源如無特殊說明,都需要本地電腦安裝OFFICE2007和PDF閱讀器。圖紙軟件為CAD,CAXA,PROE,UG,SolidWorks等.壓縮文件請下載最新的WinRAR軟件解壓。
  • 2. 本站的文檔不包含任何第三方提供的附件圖紙等,如果需要附件,請聯(lián)系上傳者。文件的所有權(quán)益歸上傳用戶所有。
  • 3. 本站RAR壓縮包中若帶圖紙,網(wǎng)頁內(nèi)容里面會有圖紙預覽,若沒有圖紙預覽就沒有圖紙。
  • 4. 未經(jīng)權(quán)益所有人同意不得將文件中的內(nèi)容挪作商業(yè)或盈利用途。
  • 5. 人人文庫網(wǎng)僅提供信息存儲空間,僅對用戶上傳內(nèi)容的表現(xiàn)方式做保護處理,對用戶上傳分享的文檔內(nèi)容本身不做任何修改或編輯,并不能對任何下載內(nèi)容負責。
  • 6. 下載文件中如有侵權(quán)或不適當內(nèi)容,請與我們聯(lián)系,我們立即糾正。
  • 7. 本站不保證下載資源的準確性、安全性和完整性, 同時也不承擔用戶因使用這些下載資源對自己和他人造成任何形式的傷害或損失。

最新文檔

評論

0/150

提交評論