使用VS2005開發自定義控件

    查看原文

注:本文參考MSDN使用 .NET Framework 開發自定義 Windows 窗體控件一節,根據該文的結構對VS2005下開發自定義控件作了一個綜合性的說明。本文將偏重於在開發自定義控件的過程中常見的難點的指導性介紹,而對MSDN中該節中已經說明的內容不會過多的重複,但會在必要的地方給出MSDN的鏈接以便你獲得更多信息。在閱讀MSDN時,初學者可以按照本文給出的鏈接閱讀相關的內容,對在本文沒有給出但在MSDN中出現的鏈接內容可以留待以後深入瞭解。

一、      爲什麼需要自定義控件

.NET Framework的概念中,控件是指具有用戶界面並實現了特定功能的一類可複用的單元.NET的所有控件都是直接或者間接從Control類繼承下來

雖然VS2005已經爲開發人員提供了衆多簡單實用的Windows窗體控件(以下統稱控件),但是在許多開發過程中,開發人員可能會遇到以下情況:

1.         應用程序中很多用戶界面具有相同或者相似的外觀和功能,並且這類界面區域中包括多個相互關聯的控件。比如常見的登陸界面都包含代表“用戶名”、“用戶密碼”、“登陸”以及“取消登陸”等的多個控件,且它們共同完成了用戶登陸的業務功能。

2.         現有的Windows控件功能基本能滿足開發的需要,但你可能希望修改其部分功能或者添加一個新的功能並在以後的開發中得到複用。比如一個只接收數字的文本框控件,可以響應條碼掃描的文本框控件等。

3.         開發中一些常用的界面外觀或者功能希望得到複用,但卻無法通過現有的Windows控件實現此目的。比如你可能在開發中需要一個具有時鐘外觀和功能的時鐘控件。

二、       自定義控件的不同種類

針對前一節出現的不同情況,Windows 窗體支持三種用戶定義的控件:複合控件、擴展控件和自定義控件。更多內容請參考MSDN自定義控件的各種不同類型

1.         複合控件

請閱讀MSDN自定義控件的各種不同類型中關於複合控件的內容。

複合控件是在.NET應用程序開發中常用且重要的一種複用手段,它的開發也相對簡單。開發複合可以從 UserControl 類派生。VS2005的“添加”菜單“用戶控件”項,它實際上就是爲用戶添加一個從UserControl類派生的自定義類。

從開發複合控件的實際過程來說,開發複合控件與開發一個普通的Window窗體(Form控件)沒有本質上的區別,UserControl類和Form類都是從System.Windows.Forms.ContainerControl繼承,它們都是通過組合已有的控件及其功能來實現特定的功能。有關更多信息,請參見開發複合 Windows 窗體控件

2.         擴展控件

請閱讀MSDN自定義控件的各種不同類型中關於擴展控件的內容。

擴展控件也是.NET應用程序開發中常用且重要的一種自定義控件開發手段。VS2005開發環境沒有給出擴展控件的“添加項”模板,開發者可以先新建一個普通的類,然後將類改爲從希望擴展其功能的現有控件類繼承,此時這個新創建的類就已經是一個自定義的擴展控件了。然後開發者可以改寫(override)基類的屬性或者方法,也可以添加自定義的屬性和方法來達到擴展控件功能的目的。比如,在WinCETools項目中的BarcodeTextBox就是從TextBox繼承並對其GotFocus等方法進行了改寫,同時也添加了IsDefault屬性、DataArrived事件等新增的功能。

3.         自定義控件

此處的“自定義控件”是指從Control類繼承從頭開始創建一個控件的過程。在本節以外的地方,如不作特別說明,“自定義控件”還是指包括複合控件、擴展控件在內的控件的統稱。

請閱讀MSDN自定義控件的各種不同類型中關於自定義控件的內容。

完全自定義開發控件是一個比較複雜的過程,開發者不僅需要完全實現控件的業務邏輯,還需要通過重寫OnPaint方法自行繪製控件的外觀。有關更多信息,請參見如何:開發簡單的 Windows 窗體控件

三、      自定義控件開發示例

你可以參照MSDN 演練:使用 Visual C# Windows 窗體控件繼承來創建一個擴展的Button控件並體會開發一個簡單的自定義控件的基本過程。

四、      控件的設計時支持

控件的設計時(design-time)支持是開發自定義控件的一個重要內容,也是開發的難點。那麼什麼是控件的設計時支持呢?

控件的設計時是指控件運行在開發環境的可視化設計器中的這一段時間,在這段時間內開發者使用它們在VS2005開發環境中設計用戶界面以及設定控件的屬性。與之相對的是控件的運行時,運行時是指應用程序編譯生成後,控件隨應用程序啓動並運行的這一階段。控件最終的是隨應用程序發佈並運行在程序的目標環境中的,爲什麼會有設計時這一概念呢?一般來說,開發者可能僅僅注意到控件必然有運行時的概念,因此也僅僅實現了控件在運行時的外觀和功能邏輯。然而,控件還有一個重要的功能,那就是開發者需要使用它們來進行用戶界面的可視化設計。在這一過程中,控件事實上也是一個運行在開發環境中的對象,這個對象由開發環境構造並銷燬,開發者通過開發環境的可視化設計器來改變控件的屬性。顯然,控件對象在運行時的外觀和邏輯是不可能和在開發環境中進行可視化設計時是完全一樣的,一個最明顯的例子就是,開發者在PC機器上的VS2005開發環境下開發WinCE應用程序,但該應用程序最終是部署在WinCE設備上運行的,因此用於開發WinCE設備應用程序的控件的設計時和運行時必然是有區別的。

瞭解了控件的設計時,那麼控件的設計時支持即是指控件在處於設計時的時候應該表現出來的形態和功能邏輯,以及向開發環境的可視化設計器提供有價值的信息的功能。從上述定義可以看出,設計時支持包含兩個方面的內容:一是可視化設計器需要的控件中的屬性(Attributes),一是控件在運行時和設計時的不同形態和功能邏輯。下面一一介紹它們。

1.         控件中的屬性(Attributes

先來看個例子。下圖所示是WinCEToolsBarcodeTextBox控件的屬性面板。

如圖中所示的控件屬性(Property)的分類和描述信息等對控件的運行時沒有任何價值,但卻給開發者使用控件帶來了很大的幫助。如何讓自己的控件提供這些信息呢?.NET提供的C#屬性(Attributes)就是解決這個問題的辦法。

在前面如何:開發簡單的 Windows 窗體控件的例子中你可能注意到了下面一段代碼:

[

Category("Alignment"),

Description("Specifies the alignment of text.")

]

publicContentAlignment TextAlignment

{

    get

    {

        return alignmentValue;

    }

    set

    {

        alignmentValue =value;

        // The Invalidate method invokes the OnPaint method described

        // in step 3.

        Invalidate();

    }

}

這段代碼中Category("Alignment")正是說明控件的TextAlignment屬性屬於Alignment類別,而Description("Specifies the alignment of text.")說明TextAlignment屬性的描述信息爲Specifies the alignment of text.

.NET爲控件的設計時提供了很多屬性(Attributes),MSDNWindows 窗體控件中的屬性列出了大部分常用的屬性,其中下列屬性(Attributes)及其用法應該最先掌握。

Ø BrowsableAttribute

Ø CategoryAttribute

Ø DefaultValueAttribute

Ø DescriptionAttribute

Ø DefaultEventAttribute

Ø DefaultPropertyAttribute

Ø ToolboxBitmapAttribute

在瞭解上述屬性(Attributes)的過程中你可能會發現,這些屬性都是.NET Framework完整版支持的類,而在.NET Compact Framework中不支持。那麼如何爲.NET Compact Framework的控件提供設計時屬性呢?VS2005爲開發者提供了另外一種解決辦法,使用“設計時屬性文件”。如下圖:

設計時屬性文件是一個XML格式的文件,它爲設備程序集提供設計時信息。先來看看下面的設計時屬性文件。

<?xmlversion="1.0"encoding="utf-16"?>

<Classesxmlns="http://schemas.microsoft.com/VisualStudio/2004/03/SmartDevices/XMTA.xsd">

 <ClassName="WinCETools.Scan.BarcodeTextBox">

    <DesktopCompatible>true</DesktopCompatible>

    <DefaultEvent>DataArrived</DefaultEvent>

    <PropertyName="IsDefault">

      <Category>WinCETools</Category>

      <DefaultValue>

        <Type>System.Boolean, mscorlib, Version=2.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089</Type>

        <Value>False</Value>

      </DefaultValue>

      <Description>獲取和設置控件是否作爲窗體中的默認掃描接收控件</Description>

      <Browsable>false</Browsable>

    </Property>

    <EventName="DataArrived">

      <Category>WinCETools</Category>

      <Description>當條碼掃描完成時觸發的事件。</Description>

    </Event>

 </Class>

</Classes>

設計時屬性文件中Classes節點是XML文件的根節點,其中每個Class節點都用於描述一個控件的設計時屬性。比如上面的文件就是對WinCETools.Scan.BarcodeTextBox這個控件的設計時屬性描述。仔細對比文件中的節點名稱和之前列出的設計時屬性(Attributes)類,我們很容易發現它們之間的對應關係。事實上,它們本身就是實現控件設計時屬性的不同方式而已。

在編譯WinCE智能設備項目的時候,VS2005首先生成項目的運行時程序集,當VS2005發現項目爲該程序集提供了設計時屬性文件時,VS2005爲程序集中的每一個類在設計時文件中查找對應的設計時屬性,然後重新爲它們編譯生成一個帶有設計時屬性的可在開發環境中運行的設計時程序集。例如爲WinCETools.Client.dll生成文件名爲WinCETools.Client.PocketPC.asmmeta.dll或者WinCETools.Client.WindowsCE.asmmeta.dll的程序集,文件名中WinCETools.Client是原程序集的名稱,asmmeta是設計時程序集固有的後綴,而PocketPCWindowsCE則分別對應項目的目標平臺。你應該爲你的控件準備各種智能設備目標平臺的設計時程序集。

2.         控件的設計時邏輯

一般來說,控件在設計時改變屬性值等過程中需要實現的邏輯僅僅是通知可視化設計器更新與該控件相關的代碼需要改動,而並不需要完全按照控件運行時應該處理的改變屬性的邏輯在開發環境中執行這些邏輯。有些更爲特殊的邏輯甚至在開發環境中根本無法執行,比如WinCETools中的BarcodeTextBox控件的IsDefault屬性,設置IsDefault屬性爲true時控件在運行時的邏輯應該是打開掃描頭,這個邏輯顯然在設計時執行會遇到困難。

鑑於上面提到的問題,控件的運行邏輯也可能分爲設計時和運行時,我們在開發控件的時候也應該加以區別。那麼如何讓控件在設計時執行設計時的邏輯,而又不影響控件在運行時的功能呢?常用的辦法是在實現控件時判斷控件當前的運行環境,然後使控件執行相應的邏輯。有兩種常見方法可以區別控件當前的運行形態:

Ø Control.Site屬性的DesignMode

控件都有一個Site屬性,Site屬性是一個ISite接口的對象,該接口的DesignMode表明控件當前的運行形態,爲true則表示控件處於設計時,否則處於運行時。

if (this.Site !=null&&this.Site.DesignMode)

{

    // 設計時邏輯

}

else

{

    // 運行時邏輯

}

Control.Site屬性不被.NET Compact Framework 1.0支持,因此通過Control.SiteDesignMode來判斷控件的設計時只能在開發非CF1.0的控件時可以採用。

Ø 判斷System.Environment.OSVersion.Platform

在開發WinCE設備控件的時候,通過判斷控件當前運行環境的操作系統平臺來判斷控件的設計時是一個簡單且有效的辦法。如下代碼:

if (System.Environment.OSVersion.Platform ==PlatformID.WinCE)

{

    // 運行時邏輯

}

else

{

    // 設計時邏輯

}

五、      關於自定義控件的更多內容

1.         控件的工具箱圖標

你可能會發現,VS2005自帶的控件工具箱上有一個友好的圖標,如何讓自己的控件在添加到工具箱後也具有一個特別的圖標呢?通過下面的步驟就可以實現這一點:

1)         製作一個bmp圖片文件,並把它命名爲和控件類名一樣的名稱;

2)         將圖片添加到項目中並把它放在和控件一樣的目錄下,使其所處的命名空間和控件一致;

3)         選中圖片並切換到屬性視圖,把“生成操作”設置爲“嵌入的資源”;

4)         編譯生成控件。

2.         開發自定義組件

.NET中,組件是從Compenent繼承下列並實現特定功能的類,控件也是組件的一種。通常把具有用戶界面的組件稱爲控件,而不具有用戶界面的稱爲組件。在VS2005下開發自定義組件和開發控件沒有大的區別,VS2005開發環境也在“添加項”中包含了一般組件的模板。在此我們不特別介紹組件的開發。

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章