1. 程式人生 > >C#自定義控制元件程式設計輕鬆入門(1)

C#自定義控制元件程式設計輕鬆入門(1)

前 言

話說,許多新手在接觸C#的時候都覺得C#使用起來特別容易方便,相對C++來說沒有那麼多的繁瑣,比如C++每次在使用一個函式,都要先在標頭檔案中宣告一遍,而C#宣告和實現都在一起,立馬可以用。而且不會一會要寫指標一會兒要寫引用,如果是遇到VC那些控制代碼就把頭給搞大。

隨著我們學習的深入,我們發現慢慢上手了,找到感覺了,於是就對C#現有的控制元件開始不那麼滿足了,提出要是有更豐富功能更強大的控制元件該多好,這樣我們就能實現更加炫更加酷的功能以及介面。
但對於新手來說,寫控制元件聽起來貌似很有難度,很高大上,問題就出在兩個地方:第一個就是自定義控制元件必須自己動手實現控制元件需要的方方方面面(如果只是簡單的事件過載估計沒有問題,關鍵的是中間還涉及到委託的使用),第二就是在實現的過程中需要GDI+的繪圖,否則控制元件無法顯示。

一、邁出第一步
有了這兩個高山橫亙在眼前,那麼很多新手就基本放棄了,實際寫自定義控制元件還是比較容易的,我只用一句話來概括你就明白了,那就是:編寫一個自定義控制元件不是每個方面都必須實現的,什麼都不做也可以。就好像我們定義一個類一樣,一個空的類也是可以正常執行的,只不過它沒有什麼功能和作用。

那麼有的人就會說,那一個空的類一個空的控制元件對於我來說有什麼作用呢?我還不如不寫!
那你就錯了,這個空的控制元件已經幫助我們邁開了編寫控制元件的第一步,而且最關鍵的是成功的打破了編寫自定義控制元件的恐懼。它的成功執行(我這裡是指不出錯的執行),已經明白得告訴你,咱們編寫自定義控制元件完全可以“量力而行”,有多少能力就實現多少功能。

比如,我基本只瞭解一些簡單的C#屬性,其餘都不瞭解,那我們也可以編寫自己的自定義控制元件,那我們就寫一個背景顏色為藍色的控制元件。
現假定我們建立了一個工程,裡面有一個From1用來呼叫測試我們的編寫的自定義控制元件,我們在工程中新增一個繼承自Control的類myControl,新增好了直接點選執行,那麼一定不會報錯,但我們會在工具欄中發現那個什麼也沒有的控制元件。
在這裡插入圖片描述
接下來我們就來實現我們的控制元件藍色背景的程式碼:

 using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using System.Windows.Forms;
using System.Drawing;

namespace userControlTest
{
    class myControl: Control
    {
        public myControl()
        {
            this.BackColor = Color.Blue;
         }
     }
}

我們拖放一個myControl控制元件到Form1上看看效果,

在這裡插入圖片描述
編譯執行後我們會發現它和我們用GDI+繪製的一個填充了的矩形沒有任何差別。對滑鼠以及鍵盤沒有任何響應。這就是我們編寫的自定義控制元件,我們已經取得了偉大的勝利,雖然是一個“醜陋的小板凳”,但它是我們自己親手做的!

當然,如果你還對事件有所瞭解,後者至少知道怎麼呼叫和過載,那麼我們就繼續來實現一個可以相應滑鼠事件的控制元件。我們假設滑鼠進入的時候背景色改變為綠色,離開的時候恢復正常即可。我們只要在myControl下過載滑鼠的相關事件,程式碼如下:

  protected override void OnMouseEnter(EventArgs e)
    {
        base.OnMouseEnter(e);

        this.BackColor = Color.Green;
    }

    protected override void OnMouseLeave(EventArgs e)
    {
        base.OnMouseLeave(e);
        this.BackColor = Color.Blue;
    }

在這裡插入圖片描述
到這裡為止,我們的摸索進展相當順利,一些都那麼自然,那麼容易。這個時候,我們回過頭來看看我們編寫的自定義控制元件在控制元件屬性框裡的表現如何,右鍵我們的控制元件,看看它的屬性:
在這裡插入圖片描述
再看看它的事件:
在這裡插入圖片描述
此時,我們發現,這些屬性和事件我們從來沒有過載更沒有新增啊,怎麼都那麼齊全完備呢?
所以到這裡,我們應該知道,編寫自定義事件其實就是在C#為我們提供的模板的基礎上進行個性化改裝,也就是說,你沒有能力改裝的地方不去動它就行了,所以編寫自定義控制元件是件很容易的事情。

有了這個理解和認識了,我們的內心是不是更強大了,不再擔心自己不能編寫自定義控制元件了吧。當然,要讓我們的控制元件功能更強大一些,更靠近我們的設計目標,擺在眼前的兩座高山是一定要征服的!

現在,假定我們有了更高的要求了,我們想通過我們自己編輯的一個控制元件屬性來控制,當我們的滑鼠進入到控制元件中時顯示的顏色,而不是我們上面的就只能是綠色,我們通過屬性可以設定為任意顏色。程式碼如下:

[Description("設定滑鼠進入時的顏色")]  // 顯示在屬性設計檢視中的描述 
[DefaultValue(typeof(Color), "Blue")] // 給予初始值 
public Color mouseEnterColor { get; set; }



protected override void OnMouseEnter(EventArgs e)
{
    base.OnMouseEnter(e);

    this.BackColor = this.mouseEnterColor; 
}

protected override void OnMouseLeave(EventArgs e)
{
    base.OnMouseLeave(e);
    this.BackColor = Color.Blue;
}

在這裡插入圖片描述
編譯一下以後,我們可以在myControl屬性中看到我們剛為控制元件增加的屬性mouseEnterColor了,我們為其設定一個顏色,這裡我們設定為粉棕色:
在這裡插入圖片描述
執行起來,我們發現果然滑鼠進入後顏色變成了我們在屬性中設定的顏色。當然,我們在程式碼中也是可以直接訪問設定了,這裡不贅述。
這裡有幾點要注意
1、如果我們要為屬性增加一個描述,如上述程式碼那樣,就必須增加一個using System.ComponentModel,否則在Description處就會報錯。
2、DefaultValueAttribute will NOT automatically set your property.
It is used for display (in bold or not) and for resetting values.
3、我們所為控制元件增加的屬性或者事件只有在編譯後拖放到Form上的才具備那些功能和屬性,編譯前拖放上去的是不具備這些屬性和功能的,別以為前面拖放會自動新增新功能,否則你會被這個“坑”徹底埋葬!
4、如果我們要設定屬性的預設值,不是在DefaultValue裡面或者通過InitializeComponent,而是通過建構函式來直接設定屬性的預設值,暫時沒有其他方法,建議不要去苦苦追尋他法。
5、我們在對Control內自帶的屬性進行操作的時候,不需要強制重新整理,系統會自動更新。但我們自定義的屬性則必須呼叫refresh強制更新。

我們現在使用的選項是系統自帶的Color型別,如果是我們自己定義的型別,要設定屬性為下拉框,則進行這樣的設定:
private ControlStyle style = ControlStyle.ComboBox;
[Description(“控制元件樣式”), DefaultValue(ControlStyle.ComboBox), Browsable(true)]

我們的自定義控制元件編寫到這裡,我們的信心更在充足了,那麼我們可以著手對其外觀進行改進了,這就需要我們瞭解GDI+的一些基本知識了,有決心攻克GDI+高山的夥伴們其實也不必害怕,可以參看我博文中的GDI+繪圖的入門篇《VS2017中GDI+繪圖輕鬆入門》,我想這些博文可以幫助你輕鬆攻克難關,這裡我們就當做你已經瞭解了GDI+。

下面我們來過載控制元件的paint事件,裝點一下控制元件的外觀,我們讓它呈現一個橢圓形,程式碼如下:
在建構函式中宣告必要的變數

RectangleF btnRec;
        private Font strFont;
        public myControl()
        {
            this.Width = 100;
            this.Height = 60;
            this.OutLineColor = Color.Yellow;
            this.fillColor = Color.YellowGreen;
            this.TextColor = Color.White;
            btnRec = new RectangleF(0, 0, this.Width, this.Height);
            strFont = new Font("宋體", 9F, FontStyle.Regular, GraphicsUnit.Point, ((byte)(134)));
        }

過載OnPaint事件,在其中繪製橢圓(並繪製控制元件標題文字)

protected override void OnPaint(PaintEventArgs pe)
    {

        base.OnPaint(pe);

        Graphics graphics = pe.Graphics;
        graphics.SmoothingMode = System.Drawing.Drawing2D.SmoothingMode.AntiAlias;
        graphics.DrawEllipse(new Pen(this.OutLineColor), btnRec);
        graphics.FillEllipse(new SolidBrush(fillColor), btnRec);
        SolidBrush b = new SolidBrush(TextColor);
        graphics.DrawString(this.Text, strFont, b, new Rectangle(20, this.Height/2-4, this.Width, this.Height));
        graphics.Dispose();
    }

最後,依然在滑鼠OnMouseEnter和OnMouseLeave中加入改變橢圓填充顏色的語句:

protected override void OnMouseEnter(EventArgs e)
        {
            base.OnMouseEnter(e);

         this.fillColor=Color.Red;
       
        this.Refresh();
    }

    protected override void OnMouseLeave(EventArgs e)
    {
        base.OnMouseLeave(e);
        this.fillColor= Color.YellowGreen;
        this.Refresh();
    }

我們看到,拖放到Form中顯示出如下圖的效果,執行起來滑鼠進入則變為紅色:
在這裡插入圖片描述
執行效果:
在這裡插入圖片描述
到這裡,我們已經取得了很大的進展,一路來,你已經是過關斬將了。下一步,我們將為我們的自定義控制元件新增自定義的事件,那將更加接近我們的設計目標了。