亚洲激情专区-91九色丨porny丨老师-久久久久久久女国产乱让韩-国产精品午夜小视频观看

溫馨提示×

溫馨提示×

您好,登錄后才能下訂單哦!

密碼登錄×
登錄注冊×
其他方式登錄
點擊 登錄注冊 即表示同意《億速云用戶服務條款》

C#如何實現自定義控件的開發

發布時間:2021-12-01 10:51:45 來源:億速云 閱讀:185 作者:小新 欄目:編程語言

這篇文章給大家分享的是有關C#如何實現自定義控件的開發的內容。小編覺得挺實用的,因此分享給大家做個參考,一起跟隨小編過來看看吧。

簡介

Smart Device Extensions for Microsoft Visual Studio .NET (SDE) 提供了一種可以在應用程序中使用的很好的基本控件。遺憾的是,嵌入式設備應用程序涉及的范圍非常廣,這就使得開發人員幾乎肯定會在某些地方缺少合適的控件,此時,基本上有兩個選擇:重新進行應用程序的結構設計以使用可用的控件,或者采用您自己的自定義控件。

SDE 的***個版本不支持設計時自定義控件,這意味著為了使用它們,必須手動編寫將它們放入窗體并設置其大小和屬性的代碼。它只需很少的額外工作量,并且只需要您接受沒有可用于自定義控件的 Form Design Support 這一事實。

問題

最近,我一直在為 Visual Studio .NET 創建類庫,用于包裝很多硬件的功能。通過使用一個可以為他們完成所有 P/Invoking 和資源管理工作的類庫,托管代碼開發人員使用這個類庫來訪問機載微型控制器和 Microsoft Windows CE 端口就容易多了。我開發用于 Graphics Master 設備的 I/O 的類庫,以便提供對兩個單獨的頭上的引腳的讀取和寫入功能。

我需要一個測試和示例應用程序,該程序能夠使用戶輕松地通過恰當的圖形接口設置或讀取數字 I/O 狀態并讀取模擬 I/O。我希望有某個東西看起來像示意圖上的接頭或類似板上的物理插頭。由于我要處理兩個物理上不同大小的接頭,所以我需要多個控件,或***是一個可以定義大小的控件。很顯然,SDE 的工具箱中沒有我想要的控件。

我本來可以使用大量的 Label、CheckBox、PictureBox 和 TextBox,但是我認為這種替代方案看起來很難看。讓我們嘗試編寫自己的控件。

C#自定義控件對象模型

***個任務是決定整個對象模型。我們需要什么樣的組成部分,這些組成部分將如何融合在一起,它們如何相互交互,如何與它們的環境交互?

 C#如何實現自定義控件的開發 

圖 1. 我的連接器控件概念

我們將創建連接器,用來包含大小可變的引腳集合,以便能夠連接不同大小的接頭。每個引腳必須有可以放在被顯示的"引腳"的左側或右側(取決于它是偶數還是奇數引腳)的標識標簽。每個引腳還可以是數字的或模擬的 I/O,因此每個引腳都需要有范圍從零到 0xFFFF 的單獨的值。***能夠一眼即可識別每個引腳的類型和值,所以將需要使用一些顏色。當然,并非接頭上的所有引腳都可用于 I/O,所以我們需要能夠禁用它們中的一部分,此外,我們希望引腳是交互的,這樣當我們接通一個引腳時,它可以做某些操作,比如更改狀態。

圖 1 是一個控件在屏幕上顯示的外觀的很好模型。

基于這些要求,我們提出了一個如圖 2 所示的對象模型。

 C#如何實現自定義控件的開發

圖 2. 控件對象模型

整體的思路是,我們將有一個 Connector 基類,然后從它派生出其他幾個自定義的 Connector 類。Connector 將包含一個 Pins 類,這個類只是通過從 CollectionBase 派生,使用索引器來公開 Pin 對象的 ListArray。

C#自定義控件:實現 Pin 對象

因為此控件的骨干是 Pin 對象,所以我們首先介紹它。Pin 對象將處理控件的大多數顯示屬性,并處理用戶交互。一旦我們可以成功地在窗體上創建、顯示單個引腳并與之交互,構建一個連接器將它們組合在一起就非常簡單了。

Pin 對象有四個在創建它時必須設置的屬性。默認的構造函數會設置它們中的每一個,但其他構造函數還可以用來允許創建者傳遞非默認的值。

最重要的屬性是 Alignment。這個屬性確定了繪制對象時文本和引腳的位置,但更重要的是,設置屬性時,它將創建和放置用于繪制引腳和文本的矩形。這些矩形的使用將在隨后解釋 OnDraw 時進行討論。

清單 1 顯示了基本構造函數和 Alignment 屬性的代碼。為引腳子組件周圍所定義的偏移量和邊框使用了常量,但這些常量也很容易成為控件的其他屬性。

清單 1. 引腳構造函數和 Alignment 屬性

public Pin()     {       showValue = false;       pinValue = 0;       type = PinType.Digital;       Alignment = PinAlignment.PinOnRight;     }     public PinAlignment Alignment     { // determines where the pin rectangle is placed       set      {         align = value;         if(value == PinAlignment.PinOnRight)         {           this.pinBorder = new Rectangle(             this.ClientRectangle.Width - (pinSize.Width + 10),             1,             pinSize.Width + 9,             this.ClientRectangle.Height - 2);             this.pinBounds = new Rectangle(             this.ClientRectangle.Width - (pinSize.Width + 5),             ((this.ClientRectangle.Height -             pinSize.Height) / 2) + 1,             pinSize.Width,             pinSize.Height);             this.textBounds = new Rectangle(             5,             5,             this.ClientRectangle.Width - (pinSize.Width + 10),             20);         }         else        {           this.pinBorder = new Rectangle(             1,             1,             pinSize.Width + 9,             this.ClientRectangle.Height - 2);             this.pinBounds = new Rectangle(             6,             this.ClientRectangle.Height - (pinSize.Height + 4),             pinSize.Width,             pinSize.Height);             this.textBounds = new Rectangle(             pinSize.Width + 10,             5,             this.ClientRectangle.Width - (pinSize.Width + 10),             20);         }         this.Invalidate();       }       get      {         return align;       }     }

由于 Pin 對象不會提供很好的用戶交互或可自定義性,所以引腳的核心功能是我們將重寫的繪圖例程 OnDraw,重寫該例程是為了可以由我們來繪制整個引腳。

每個引腳將繪制三個部分:引腳本身將是一個圓(除非它是 Pin 1,這時它將是一個方塊),我們將圍繞引腳繪制邊框矩形,然后在引腳的左側或右側留出一個區域用來繪制引腳的文本。

要繪制引腳,我們首先確定表示實際引腳的圓所使用的顏色。如果引腳被禁用,它的顏色是灰色。如果啟用,則要確定它是什么類型。模擬引腳將是綠色,而數字引腳根據情況而不同,如果是低 (關)則是藍色,如果是高(開)則是橙色。

下一步,我們使用 FillEllipse 來繪制所有實際的引腳,但 PinNumber=1 時除外,這時使用 FillRectangle 繪制引腳。通過繪制在矩形 (pinBounds) 中而不是控件的邊界上,我們能夠在創建引腳時設置引腳的位置(左側或右側),并且從這一點開始,我們可以在不用關心引腳的位置的情況下進行繪制。

下一步我們繪制標簽,它將是引腳的文本或引腳的值,這取決于 ShowValue 屬性。

我們使用與繪制引腳時類似的策略來繪制文本,但這次我們必須計算水平和垂直偏移量,因為在 Microsoft .NET 壓縮框架中,DrawText 方法不允許有 TextAlign 參數。

最終,我們通過調用 Dispose 方法清理我們手動使用的 Brush 對象。

清單 2 顯示了完整的 OnDraw 例程。

清單 2. OnDraw() 方法

 protected override void OnPaint(PaintEventArgs pe)  {    Brush b;          // determine the Pin color    if(this.Enabled)    {      if(type == PinType.Digital)      {        // digital pins have different on/off color        b = new System.Drawing.SolidBrush(        this.Value == 0 ? (digitalOffColor) : (digitalOnColor));      }      else     {        // analog pin        b = new System.Drawing.SolidBrush(analogColor);      }    }    else   {      // disabled pin      b = new System.Drawing.SolidBrush(disabledColor);    }    // draw the pin    if(this.PinNumber == 1)      pe.Graphics.FillRectangle(b, pinBounds);    else     pe.Graphics.FillEllipse(b, pinBounds);    // draw a border Rectangle around the pin    pe.Graphics.DrawRectangle(new Pen(Color.Black), pinBorder);    // draw the text centered in the text bound    string drawstring;    // are we showing the Text or Value?    if(showValue)      drawstring = Convert.ToString(this.Value);    else     drawstring = this.Text;    // determine the actual string size    SizeF fs = pe.Graphics.MeasureString(          drawstring,          new Font(FontFamily.GenericMonospace, 8f,                   FontStyle.Regular));    // draw the string    pe.Graphics.DrawString(        drawstring,        new Font(FontFamily.GenericMonospace, 8f,        FontStyle.Regular),        new SolidBrush((showValue ? analogColor : Color.Black)),        textBounds.X + (textBounds.Width - fs.ToSize().Width) / 2,        textBounds.Y + (textBounds.Height - fs.ToSize().Height) /                   2);    // clean up the Brush    b.Dispose();    }  }

構建 Pin 類的***一步是添加 Click 處理程序。對于我們的 Pin 類來說,我們將使用自定義的 EventArg,以便可以向事件處理程序傳遞引腳的文本和編號。要創建自定義的 EventArg,我們只是創建了一個從 EventArgs 類派生的類:

public class PinClickEventArgs : EventArgs  {    // a PinClick passes the Pin Number and the Pin's Text    public int number;    public string text;    public PinClickEventArgs(int PinNumber, string PinText)    {      number = PinNumber;      text = PinText;    }  }

下一步,我們將一個委托添加到命名空間中:

public delegate void PinClickHandler(Pin source, PinClickEventArgs args);

現在,我們需要添加代碼來確定什么時候發生單擊,然后引發事件。對于我們的 Pin 類,當引腳的邊框矩形內部發生 MouseDown 和 MouseUp 事件時即為一個邏輯上的單擊 - 這樣,如果用戶單擊引腳的文本部分,則不會觸發 Click 事件,但如果點擊表示實際引腳的區域,則觸發該事件。

首先,我們需要一個公共 PinClickHandler 事件,其定義如下:

public event PinClickHandler PinClick;

我們還需要一個私有的布爾變量,我們將在 MouseDown 事件發生時設置該變量,用于指示我們正在單擊過程中。然后,我們檢查 MouseUp 事件的該變量,以確定事件是否是按連續的順序發生的:

bool midClick;

下一步,我們需要為 MouseDown 和 MouseUp 添加兩個事件處理程序,如清單 3 所示。

清單 3. 用于實現 PinClick 事件的事件處理程序

private void PinMouseDown(object sender, MouseEventArgs e)     {       if(!this.Enabled)         return;       // if the user clicked in the "pin" rectangle, start a click process       midClick = pinBorder.Contains(e.X, e.Y);     }     private void PinMouseUp(object sender, MouseEventArgs e)     {       // if we had a mousedown and then up inside the "pin" rectangle,       // fire a click       if((midClick) && (pinBorder.Contains(e.X, e.Y)))       {         if(PinClick != null)           PinClick(this, new PinClickEventArgs(                    this.PinNumber, this.Text));       }     }

***,我們需要為每個引腳實現事件處理程序。引腳的基本構造函數是添加這些掛鉤的好地方,我們可以通過直接在構造函數中添加以下代碼來完成:view plaincopy to clipboardprint?this.MouseDown += new MouseEventHandler(PinMouseDown);   this.MouseUp += new MouseEventHandler(PinMouseUp);  this.MouseDown += new MouseEventHandler(PinMouseDown);

this.MouseUp += new MouseEventHandler(PinMouseUp); 實現 Pins 類一旦有了 Pin 類,就可以創建從 CollectionBase 派生的 Pins 類。該類的目的是提供索引器,這樣我們就可以很容易在集合內添加、刪除和操縱 Pin 類。

清單 4. Pins 類

public class Pins : CollectionBase  {    public void Add(Pin PinToAdd)    {      List.Add(PinToAdd);    }    public void Remove(Pin PinToRemove)    {      List.Remove(PinToRemove);    }    // Indexer for Pins    public Pin this[byte Index]    {      get     {        return (Pin)List[Index];      }      set     {        List[Index] = value;      }    }    public Pins(){}  }

實現 Connector 類既然我們已經獲得了 Pins 類,我們現在需要構建 Connector 類,該類將是一個簡單的包裝類,這個包裝類包含 Pins 類,并在每個引腳和連接器容器之間封送 PinClick 事件,而且它有一個表示連接器上的引腳數的構造函數。清單 5 顯示了完整的 Connector 類。

清單 5. Connector 類

public class Connector : System.Windows.Forms.Control  {    public event PinClickHandler PinClick;    protected Pins pins;    byte pincount;    public Connector(byte TotalPins)    {      pins = new Pins();      pincount = TotalPins;      InitializeComponent();    }    private void InitializeComponent()    {      for(int i = 0 ; i <  pincount ; i++)      {        Pin p = new Pin(PinType.Digital,              (PinAlignment)((i + 1) % 2), 0);        p.PinClick += new PinClickHandler(OnPinClick);        p.PinNumber = i + 1;        p.Text = Convert.ToString(i);        p.Top = (i / 2) * p.Height;        p.Left = (i % 2) * p.Width;        this.Pins.Add(p);        this.Controls.Add(p);      }      this.Width = Pins[0].Width * 2;      this.Height = Pins[0].Height * this.Pins.Count / 2;    }    public Pins Pins    {      set     {        pins = value;      }      get     {        return pins;      }    }    private void OnPinClick(Pin sender, PinClickEventArgs e)    {      // pass on the event      if(PinClick != null)      {        PinClick(sender, e);        if(sender.Type == PinType.Digital)          sender.Value = sender.Value == 0 ? 1 : 0;        else         sender.DisplayValue = !sender.DisplayValue;      }    }    protected override void Dispose( bool disposing )    {      base.Dispose( disposing );    }  }

Connector 的 InitializeComponent 方法是創建所有被包含的 Pin 類并將其添加到連接器的控件中的地方,并且是連接器本身調整大小的地方。InitializeComponent 也是最終被 Form Designer 用來顯示我們的連接器的方法。

C#自定義控件:構建自定義連接器

Connector 類本身很簡單,它不會修改任何默認的引腳設置。但是,我們現在可以通過從 Connector 類派生新的類,從而構建一個自定義連接器,并修改單個引腳(例如,使某些引腳成為模擬引腳,或將其禁用)。

在示例應用程序中,我為 Applied Data Systems 的 Graphics Master 板創建了兩個連接器,一個用于 J2,一個用于 J7。構造函數基于連接器設置引腳的類型以及引腳的文本。圖 2 是窗體上有 J2 和 J7 的示例應用程序的屏幕快照。

C#如何實現自定義控件的開發

圖 3. 使用兩個 Connector 對象的窗體

感謝各位的閱讀!關于“C#如何實現自定義控件的開發”這篇文章就分享到這里了,希望以上內容可以對大家有一定的幫助,讓大家可以學到更多知識,如果覺得文章不錯,可以把它分享出去讓更多的人看到吧!

向AI問一下細節

免責聲明:本站發布的內容(圖片、視頻和文字)以原創、轉載和分享為主,文章觀點不代表本網站立場,如果涉及侵權請聯系站長郵箱:is@yisu.com進行舉報,并提供相關證據,一經查實,將立刻刪除涉嫌侵權內容。

AI

西昌市| 乐至县| 邯郸市| 庆安县| 临泉县| 怀来县| 盐津县| 仙居县| 安多县| 蛟河市| 黄平县| 乌鲁木齐县| 孙吴县| 贞丰县| 苏尼特右旗| 广安市| 横山县| 墨江| 尖扎县| 襄汾县| 图们市| 十堰市| 仁怀市| 台前县| 茌平县| 泰顺县| 万荣县| 巴塘县| 福建省| 峨边| 双牌县| 山东省| 文成县| 竹北市| 十堰市| 安新县| 麻城市| 上杭县| 同德县| 和龙市| 五家渠市|