天天看點

C#制作WinForm控件

<a href="http://www.cnblogs.com/Dragon-China/archive/2007/12/17/1001386.html">C#制作WinForm控件</a>

轉:http://www.cnblogs.com/salonliudong/archive/2007/04/29/732524.html

自定義控件基礎知識

一、概述

C#制作WinForm控件

· 組合現有控件來創作一個複合控件。

C#制作WinForm控件

· 擴充現有控件,對其進行自定義或為其添加功能。

可以通過從任何 Windows 窗體控件派生控件并重寫或添加屬性、方法和事件的方式來自定義 Windows 窗體控件。

· 創作一個不是通過組合或擴充現有控件而形成的控件。

C#制作WinForm控件

Windows 窗體控件的基類 System.Windows.Forms.Control 為用戶端 Windows 應用程式中的外觀顯示提供了所需的途徑。Control 提供了一個視窗句柄,用來處理消息路由并提供滑鼠和鍵盤事件及許多其他使用者界面事件。還提供了進階布局,并具有用于外觀顯示的特定屬性,如 ForeColor、BackColor、Height、Width 和許多其他屬性。此外,它還提供了安全性、線程支援以及與 ActiveX 控件的互動性。由于基類提供了很多基礎結構,使得開發自己的 Windows 窗體控件變得相對簡單。

<a>二、編寫簡單的自定義控件</a>

下面的示例建立一個簡單控件,該控件通過處理 Paint 事件顯示其 Text 屬性的值。為了建立此控件和處理事件,必須建立一個從 Control 繼承的類,并建立一個重寫 OnPaint 方法的方法。

C#制作WinForm控件

public class HelloWorldControl : Control

C#制作WinForm控件

 {

C#制作WinForm控件

protected override void OnPaint(PaintEventArgs e)

C#制作WinForm控件
C#制作WinForm控件

        RectangleF rect = new RectangleF(ClientRectangle.X,

C#制作WinForm控件

                                         ClientRectangle.Y,

C#制作WinForm控件

                                         ClientRectangle.Width,

C#制作WinForm控件

                                         ClientRectangle.Height);

C#制作WinForm控件
C#制作WinForm控件

        e.Graphics.DrawString(this.Text, Font, new SolidBrush(ForeColor), rect);

C#制作WinForm控件

    }

C#制作WinForm控件

}

C#制作WinForm控件

2.2、我們在VS2005中建立自定義控件的步驟:

1. 打開vs2005,檔案/建立/項目。

2. 出現“建立項目”對話框。

3. 在“名稱”框中,鍵入項目名稱,“位置”框選擇要存儲的位置。

4. 從“語言”清單中選擇要使用的程式設計語言。

5. 單擊“添加”,這時一個自定義控件工程已經建成,生成一下,就制作了一個簡單的自定義控件,隻不過沒有任何功能。

6. 向新使用者控件添加任何标記和控件,并為該使用者控件添加執行的所有任務(例如,處理控件事件或從資料源讀取資料)添加代碼。

2.3、檢查控件的設計時行為

1. 啟動 VS2005。

2. 通過從“檔案”菜單單擊/建立/項目/Windows應用程式,添加新窗體。

3. 右鍵“工具箱/選擇項…”,在彈出的“選擇工具箱項”對話框中點下面的浏覽按鈕選擇要使用控件的 DLL;确定後,該控件出現在工具箱的底部。

4. 選擇該控件并将其添加到窗體中。将看到該控件出現在窗體上。

5. 如果從上一個示例添加控件,您将注意到即使如此簡單的控件都具有一整套屬性和廣泛的設計時行為。此預設行為是從 Control 類繼承的。

三、為控件添加屬性

控件應該定義屬性而不是公共字段,因為可視化設計器在屬性浏覽器中顯示屬性,而不顯示字段。屬性就像智能字段。屬性通常具有帶通路函數的專用資料成員,在文法上屬性被作為類的字段進行通路。(雖然屬性可以具有不同的通路級别,但此處的讨論将重點放在公共通路這種更加常見的情況上。

屬性定義通常由以下兩部分組成: 

1、專用資料成員的定義。

   private int number = 0;

2、使用屬性聲明文法對公共屬性進行的定義。

該文法通過 get 和 set 通路函數将專用資料成員和公共屬性關聯起來。

C#制作WinForm控件

        public int MyNumber 

C#制作WinForm控件

    {

C#制作WinForm控件

    get 

C#制作WinForm控件

       { 

C#制作WinForm控件

          return number; 

C#制作WinForm控件

       }    

C#制作WinForm控件

    set 

C#制作WinForm控件
C#制作WinForm控件

          number = value;

C#制作WinForm控件

       }

C#制作WinForm控件
C#制作WinForm控件

value 這個術語是屬性定義文法中的一個關鍵字。在呼叫代碼中,将變量 value 配置設定給屬性。value 的類型必須同它被配置設定到的屬性的聲明類型相同。

雖然屬性定義中通常包含專用資料成員,但這不是必需的。get 通路器不用通路私有資料成員就可以傳回值。get 方法傳回系統時間的屬性就屬于這種情況。屬性啟用資料隐藏,通路器方法隐藏屬性的實作。

定義屬性時需考慮以下重要的注意事項:

1、   必須将屬性應用于定義的屬性。屬性用來指定設計器顯示屬性的方式。

2、   如果改變屬性将影響控件的外觀顯示,請從 set 通路器中調用 Invalidate 方法(從 Control 繼承該方法)。Invalidate 随後調用 OnPaint 方法,該方法将重新繪制控件。為提高效率起見,對 Invalidate 的多次調用将産生對 OnPaint 的一次調用。

3、   .NET Framework 類庫為常見資料類型(如整數、小數、布爾值和其他資料)提供了類型轉換器。類型轉換器的目的通常是用來提供字元串到數值的轉換(從字元串資料轉換為其他資料類型)。常見資料類型與預設類型轉換器(将數值轉換為字元串,并将字元串轉換為相應資料類型)相關聯。如果定義了自定義(即,非标準)資料類型的屬性,則應用的屬性必須将類型轉換器指定為與該屬性相關聯。還可以使用屬性使自定義 UI 類型編輯器與某個屬性相關聯。UI 類型編輯器提供了一個用來編輯屬性或資料類型的使用者界面。顔色選擇器是 UI 類型編輯器的一個示例。

例:首先建立一個名為 DrawingMode 的簡單枚舉。

C#制作WinForm控件

        public enum DrawingMode

C#制作WinForm控件

        {

C#制作WinForm控件

            Happy = 0,

C#制作WinForm控件

            Sad = 1,

C#制作WinForm控件

            Angry = 2

C#制作WinForm控件

        }

C#制作WinForm控件

接着,向該控件添加 MyDrawingMode 屬性。

C#制作WinForm控件

       private DrawingMode myDrawingMode;

C#制作WinForm控件

       [Browsable(true), Category("Appearance")]

C#制作WinForm控件

        public DrawingMode MyDrawingMode

C#制作WinForm控件
C#制作WinForm控件

            get

C#制作WinForm控件

            {

C#制作WinForm控件

                return myDrawingMode;

C#制作WinForm控件

            }

C#制作WinForm控件

            set

C#制作WinForm控件
C#制作WinForm控件

                myDrawingMode = value;

C#制作WinForm控件

                SetColors();

C#制作WinForm控件
C#制作WinForm控件
C#制作WinForm控件

對 SetColors 方法的調用隻是根據 myDrawingMode 的值設定控件的 BackColor 和 ForeColor。向控件添加下面的代碼。

C#制作WinForm控件

        private void SetColors()

C#制作WinForm控件
C#制作WinForm控件

            switch (myDrawingMode)

C#制作WinForm控件
C#制作WinForm控件

                case DrawingMode.Happy:

C#制作WinForm控件

                    this.BackColor = Color.Yellow;

C#制作WinForm控件

                    this.ForeColor = Color.Green;

C#制作WinForm控件

                    break;

C#制作WinForm控件

                case DrawingMode.Sad:

C#制作WinForm控件

                    this.BackColor = Color.LightSlateGray;

C#制作WinForm控件

                    this.ForeColor = Color.White;

C#制作WinForm控件
C#制作WinForm控件

                case DrawingMode.Angry:

C#制作WinForm控件

                    this.BackColor = Color.Red;

C#制作WinForm控件

                    this.ForeColor = Color.Teal;

C#制作WinForm控件
C#制作WinForm控件

                default:

C#制作WinForm控件

                    this.BackColor = Color.Black;

C#制作WinForm控件
C#制作WinForm控件
C#制作WinForm控件
C#制作WinForm控件
C#制作WinForm控件

現在可以向控件的paint方法添加代碼,來繪制控件的樣式,也可以添加現有的控件來組合實作想要的功能(例子裡面有)。

C#制作WinForm控件

        private void UserControl1_Paint(object sender, PaintEventArgs e)

C#制作WinForm控件
C#制作WinForm控件

            Graphics curG = e.Graphics;

C#制作WinForm控件

            Pen curPen = new Pen(Color.Black);

C#制作WinForm控件

            Rectangle curRect = new Rectangle(0, 0, Width - 2, Height - 3);

C#制作WinForm控件

            curG.DrawRectangle(curPen, curRect);

C#制作WinForm控件

            curG.DrawEllipse(curPen, curRect);

C#制作WinForm控件
C#制作WinForm控件

四、為控件添加添加事件

事件(Event)

事件是對象發送的消息,以發信号通知操作的發生。操作可能是由使用者互動(例如滑鼠單擊)引起的,也可能是由某些其他的程式邏輯觸發的。引發事件的對象稱為事件發送方。捕獲事件并對其作出響應的對象叫做事件接收方。

在事件通信中,事件發送方類不知道哪個對象或方法将接收到(處理)它引發的事件。所需要的是在源和接收方之間存在一個媒介(或類似指針的機制)。.NET Framework 定義了一個特殊的類型(Delegate),該類型提供函數指針的功能。

代理(delegate)

delegate是C#中的一種類型,它實際上是一個能夠持有對某個方法的引用的類。與其它的類不同,delegate類能夠擁有一個簽名(signature),并且它隻能持有與它的簽名相比對的方法的引用。這樣,代理就等效于一個類型安全函數指針或一個回調。它允許你傳遞一個類A的方法m給另一個類B的對象,使得類B的對象能夠調用這個方法m。但與函數指針相比,delegate有許多函數指針不具備的優點。首先,函數指針隻能指向靜态函數,而delegate既可以引用靜态函數,又可以引用非靜态成員函數。在引用非靜态成員函數時,delegate不但儲存了對此函數入口指針的引用,而且還儲存了調用此函數的類執行個體的引用。其次,與函數指針相比,delegate是面向對象、類型安全、可靠的受控(managed)對象。也就是說,runtime能夠保證delegate指向一個有效的方法,你無須擔心delegate會指向無效位址或者越界位址。

實作一個delegate是很簡單的,通過以下3個步驟即可實作一個delegate:

1. 聲明一個delegate對象,它應當與你想要傳遞的方法具有相同的參數和傳回值類型。

2. 建立delegate對象,并将你想要傳遞的函數作為參數傳入。

3. 在要實作異步調用的地方,通過上一步建立的對象來調用方法。

下面是一個簡單的例子:

C#制作WinForm控件

public class MyDelegateTest 

C#制作WinForm控件

C#制作WinForm控件

    // 步驟1,聲明delegate對象 

C#制作WinForm控件

    public delegate void MyDelegate(string name); 

C#制作WinForm控件

    // 這是我們欲傳遞的方法,它與MyDelegate具有相同的參數和傳回值類型 

C#制作WinForm控件

    public static void MyDelegateFunc(string name) 

C#制作WinForm控件

    { 

C#制作WinForm控件

        Console.WriteLine("Hello, {0}", name); 

C#制作WinForm控件

    } 

C#制作WinForm控件

    public static void Main () 

C#制作WinForm控件
C#制作WinForm控件

        // 步驟2,建立delegate對象 

C#制作WinForm控件

      MyDelegate md = new MyDelegate(MyDelegateTest.MyDelegateFunc); 

C#制作WinForm控件

        // 步驟3,調用delegate 

C#制作WinForm控件

        md("sam1111"); 

C#制作WinForm控件
C#制作WinForm控件
C#制作WinForm控件

事件處理

C#中的事件處理實際上是一種具有特殊簽名的delegate,象下面這個樣子:

public delegate void MyEventHandler(object sender, MyEventArgs e);

其中的兩個參數,sender代表事件發送者,e是事件參數類。MyEventArgs類用來包含與事件相關的資料,所有的事件參數類都必須從System.EventArgs類派生。當然,如果你的事件不含特别的參數,那麼可以直接用System.EventArgs類作為參數。

結合delegate的實作,我們可以将自定義事件的實作歸結為以下幾步:

1:定義delegate對象類型,它有兩個參數,第一個參數是事件發送者對象,第二個參數是事件參數類對象。

2:定義事件參數類,此類應當從System.EventArgs類派生。如果事件不帶參數,這一步可以省略。

3:定義事件處理方法,它應當與delegate對象具有相同的參數和傳回值類型。

4:用event關鍵字定義事件對象,它同時也是一個delegate對象。

5:用+=操作符添加事件到事件隊列中(-=操作符能夠将事件從隊列中删除)。

6:在需要觸發事件的地方用調用delegate的方式寫事件觸發方法。一般來說,此方法應為protected通路限制,既不能以public方式調用,但可以被子類繼承。名字是可以是OnEventName。

7:在适當的地方調用事件觸發方法觸發事件。

下面是一個例子,例子模仿容器和控件的模式,由控件觸發一個事件,在容器中捕捉并且進行處理。

事件的觸發者:

C#制作WinForm控件

/// &lt;summary&gt;

C#制作WinForm控件

/// 事件的觸發者

C#制作WinForm控件

/// &lt;/summary&gt;

C#制作WinForm控件

public class Control

C#制作WinForm控件

{

C#制作WinForm控件

    public delegate void SomeHandler(object sender, System.EventArgs e);

C#制作WinForm控件

    public event SomeHandler SomeEvent;

C#制作WinForm控件

    public Control()

C#制作WinForm控件
C#制作WinForm控件

        //這裡使用的delegate必須與事件中聲名的一緻

C#制作WinForm控件

        this.SomeEvent += new SomeHandler(this.ProcessSomeEvent);

C#制作WinForm控件
C#制作WinForm控件

    public void RaiseSomeEvent()

C#制作WinForm控件
C#制作WinForm控件

        EventArgs e = new EventArgs();

C#制作WinForm控件

        Console.Write("Please input 'a':");

C#制作WinForm控件

        string s = Console.ReadLine();

C#制作WinForm控件

        //在使用者輸入一個小a的情況下觸發事件,否則不觸發

C#制作WinForm控件

        if (s == "a")

C#制作WinForm控件
C#制作WinForm控件

            SomeEvent(this, e);

C#制作WinForm控件
C#制作WinForm控件
C#制作WinForm控件

    //事件的觸發者自己對事件進行處理,這個方法的參數必須和代理中聲名的一緻

C#制作WinForm控件

    private void ProcessSomeEvent(object sender, EventArgs e)

C#制作WinForm控件
C#制作WinForm控件

        Console.WriteLine("hello");

C#制作WinForm控件
C#制作WinForm控件
C#制作WinForm控件

事件的接收者:

C#制作WinForm控件
C#制作WinForm控件

/// 事件的接收和處理者

C#制作WinForm控件
C#制作WinForm控件

class Container

C#制作WinForm控件
C#制作WinForm控件

    private Control ctrl = new Control();

C#制作WinForm控件

   public Container()

C#制作WinForm控件
C#制作WinForm控件
C#制作WinForm控件

        ctrl.SomeEvent += new Control.SomeHandler(this.ResponseSomeEvent);

C#制作WinForm控件

        ctrl.RaiseSomeEvent();

C#制作WinForm控件
C#制作WinForm控件

    public static void Main()

C#制作WinForm控件
C#制作WinForm控件

        Container pane = new Container();

C#制作WinForm控件

        Console.ReadLine();

C#制作WinForm控件
C#制作WinForm控件

    //這是事件的接受者對事件的響應

C#制作WinForm控件

    private void ResponseSomeEvent(object sender, EventArgs e)

C#制作WinForm控件
C#制作WinForm控件

        Console.WriteLine("Some event occur!");

C#制作WinForm控件
C#制作WinForm控件
C#制作WinForm控件

程式運作的結果如下:

please input 'a':a

hello

Some event occur!

五、其他屬性設定

   自定義控件工程建立, 控件設定,屬性事件的添加完成以後,生成項目,控件就已經制作完成了,可以在測試工程中使用,這裡還有許多設定屬性,需要我們了解,比如(下圖)我們自己制作的控件顯示的圖示總是一個齒輪。

C#制作WinForm控件

   而我們看到的工具箱上的每個控件都有自己的圖示,我們可以通過下面語句為自己制作的控件添加圖示。

C#制作WinForm控件

[ToolboxBitmap(@"D:"Program Files"qq"AirDLIcon"1381love.ico")]

C#制作WinForm控件

public partial class UserControl1 : UserControl

C#制作WinForm控件

{………….}

C#制作WinForm控件

即在控件類前面加上ToolboxBitmap屬性,屬性參數指向一個圖檔的位址就可以了,加上這句程式以後,生成的控件如下圖,圖示變成了一個漂亮的心。

C#制作WinForm控件

再比如,我自己定義了一個屬性,如果不進行設定,是不會在屬性視窗顯示的,也就是我們在用控件的時候不能夠通過可視化的界面對其進行設定,想讓它在屬性視窗顯示,就要用Browsable屬性了,如下面的例子。

C#制作WinForm控件

        public enum DrawingMode{Happy = 0,Sad = 1,Angry = 2}

C#制作WinForm控件

        private DrawingMode myDrawingMode;

C#制作WinForm控件

        [Browsable(true)]

C#制作WinForm控件
C#制作WinForm控件
C#制作WinForm控件
C#制作WinForm控件
C#制作WinForm控件
C#制作WinForm控件
C#制作WinForm控件
C#制作WinForm控件
C#制作WinForm控件
C#制作WinForm控件
C#制作WinForm控件

  }

C#制作WinForm控件
C#制作WinForm控件

像這樣的屬性還可以組合使用,例如上面的例子,我在Browsable屬性後面再加上一個Category屬性,讓它的參數等于Appearance,這時我們自己定義的屬性就從屬性框中的雜項轉到了外觀項裡面了,如圖:

C#制作WinForm控件

[Browsable(true), Category("Appearance")]

C#制作WinForm控件

public DrawingMode MyDrawingMode

C#制作WinForm控件
C#制作WinForm控件
C#制作WinForm控件
C#制作WinForm控件
C#制作WinForm控件
C#制作WinForm控件
C#制作WinForm控件
C#制作WinForm控件
C#制作WinForm控件
C#制作WinForm控件
C#制作WinForm控件
C#制作WinForm控件

像這樣的屬性有很多,我主要羅列下面這些,在使用的時候大家可以參照。

Browsable

适用于屬性和事件,指定屬性或事件是否應該顯示在屬性浏覽器中。

Category

 适用于屬性和事件,指定類别的名稱,在該類别中将對屬性或事件進行分組。當使用了類别時,元件屬性和事件可以按邏輯分組顯示在屬性浏覽器中。

Description

适用于屬性和事件,定義一小塊文本,該文本将在使用者選擇屬性或事件時顯示在屬性浏覽器底部。

Bindable

适用于屬性 指定是否要綁定到該屬性。

DefaultProperty

适用于屬性,(将此特性插入類聲明前。)指定元件的預設屬性。當使用者單擊控件時,将在屬性浏覽器中標明該屬性。

DefaultValue

 适用于屬性,為屬性設定一個簡單的預設值。

Editor

 适用于屬性,指定在可視設計器中編輯(更改)屬性時要使用的編輯器。

Localizable

 适用于屬性,指定屬性可本地化。當使用者要本地化某個窗體時,任何具有該特性的屬性都将自動永久駐留到資源檔案中。

DesignerSerializationVisibility

适用于屬性,指定顯示在屬性浏覽器中的屬性是否應該(以及如何)永久駐留在代碼中。

TypeConverter

适用于屬性,指定将屬性的類型轉換為另一個資料類型時要使用的類型轉換器。

DefaultEvent

 适用于事件,(将此特性插入類聲明前。)指定元件的預設事件。這是當使用者單擊元件時在屬性浏覽器中標明的事件。 

本文轉自94cool部落格園部落格,原文連結:http://www.cnblogs.com/94cool/articles/1524892.html,如需轉載請自行聯系原作者

繼續閱讀