偷偷摘套内射激情视频,久久精品99国产国产精,中文字幕无线乱码人妻,中文在线中文a,性爽19p

C#自定義控件的開(kāi)發(fā):Pin和Connector

開(kāi)發(fā) 后端
本文介紹了如何使用智能設(shè)備擴(kuò)展C#自定義控件。

適用于:Microsoft Windows CE .NET/Smart Device Extensions for Microsoft Visual Studio .NET

簡(jiǎn)介

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

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

問(wèn)題

最近,我一直在為 Visual Studio .NET 創(chuàng)建類(lèi)庫(kù),用于包裝很多硬件的功能。通過(guò)使用一個(gè)可以為他們完成所有 P/Invoking 和資源管理工作的類(lèi)庫(kù),托管代碼開(kāi)發(fā)人員使用這個(gè)類(lèi)庫(kù)來(lái)訪(fǎng)問(wèn)機(jī)載微型控制器和 Microsoft Windows CE 端口就容易多了。我開(kāi)發(fā)用于 Graphics Master 設(shè)備的 I/O 的類(lèi)庫(kù),以便提供對(duì)兩個(gè)單獨(dú)的頭上的引腳的讀取和寫(xiě)入功能。

我需要一個(gè)測(cè)試和示例應(yīng)用程序,該程序能夠使用戶(hù)輕松地通過(guò)恰當(dāng)?shù)膱D形接口設(shè)置或讀取數(shù)字 I/O 狀態(tài)并讀取模擬 I/O。我希望有某個(gè)東西看起來(lái)像示意圖上的接頭或類(lèi)似板上的物理插頭。由于我要處理兩個(gè)物理上不同大小的接頭,所以我需要多個(gè)控件,或***是一個(gè)可以定義大小的控件。很顯然,SDE 的工具箱中沒(méi)有我想要的控件。

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

C#自定義控件對(duì)象模型

***個(gè)任務(wù)是決定整個(gè)對(duì)象模型。我們需要什么樣的組成部分,這些組成部分將如何融合在一起,它們?nèi)绾蜗嗷ソ换?,如何與它們的環(huán)境交互?

 我的連接器控件概念  

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

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

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

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

 控件對(duì)象模型

圖 2. 控件對(duì)象模型

整體的思路是,我們將有一個(gè) Connector 基類(lèi),然后從它派生出其他幾個(gè)自定義的 Connector 類(lèi)。Connector 將包含一個(gè) Pins 類(lèi),這個(gè)類(lèi)只是通過(guò)從 CollectionBase 派生,使用索引器來(lái)公開(kāi) Pin 對(duì)象的 ListArray。

C#自定義控件:實(shí)現(xiàn) Pin 對(duì)象

因?yàn)榇丝丶墓歉墒?Pin 對(duì)象,所以我們首先介紹它。Pin 對(duì)象將處理控件的大多數(shù)顯示屬性,并處理用戶(hù)交互。一旦我們可以成功地在窗體上創(chuàng)建、顯示單個(gè)引腳并與之交互,構(gòu)建一個(gè)連接器將它們組合在一起就非常簡(jiǎn)單了。

Pin 對(duì)象有四個(gè)在創(chuàng)建它時(shí)必須設(shè)置的屬性。默認(rèn)的構(gòu)造函數(shù)會(huì)設(shè)置它們中的每一個(gè),但其他構(gòu)造函數(shù)還可以用來(lái)允許創(chuàng)建者傳遞非默認(rèn)的值。

最重要的屬性是 Alignment。這個(gè)屬性確定了繪制對(duì)象時(shí)文本和引腳的位置,但更重要的是,設(shè)置屬性時(shí),它將創(chuàng)建和放置用于繪制引腳和文本的矩形。這些矩形的使用將在隨后解釋 OnDraw 時(shí)進(jìn)行討論。

清單 1 顯示了基本構(gòu)造函數(shù)和 Alignment 屬性的代碼。為引腳子組件周?chē)x的偏移量和邊框使用了常量,但這些常量也很容易成為控件的其他屬性。

清單 1. 引腳構(gòu)造函數(shù)和 Alignment 屬性

  1. public Pin()     
  2. {     
  3.   showValue = false;     
  4.   pinValue = 0;     
  5.   type = PinType.Digital;     
  6.   Alignment = PinAlignment.PinOnRight;     
  7. }     
  8. public PinAlignment Alignment     
  9. // determines where the pin rectangle is placed     
  10.   set    
  11.   {     
  12.     align = value;     
  13.     if(value == PinAlignment.PinOnRight)     
  14.     {     
  15.       this.pinBorder = new Rectangle(     
  16.         this.ClientRectangle.Width - (pinSize.Width + 10),     
  17.         1,     
  18.         pinSize.Width + 9,     
  19.         this.ClientRectangle.Height - 2);     
  20.         this.pinBounds = new Rectangle(     
  21.         this.ClientRectangle.Width - (pinSize.Width + 5),     
  22.         ((this.ClientRectangle.Height -     
  23.         pinSize.Height) / 2) + 1,     
  24.         pinSize.Width,     
  25.         pinSize.Height);     
  26.         this.textBounds = new Rectangle(     
  27.         5,     
  28.         5,     
  29.         this.ClientRectangle.Width - (pinSize.Width + 10),     
  30.         20);     
  31.     }     
  32.     else    
  33.     {     
  34.       this.pinBorder = new Rectangle(     
  35.         1,     
  36.         1,     
  37.         pinSize.Width + 9,     
  38.         this.ClientRectangle.Height - 2);     
  39.         this.pinBounds = new Rectangle(     
  40.         6,     
  41.         this.ClientRectangle.Height - (pinSize.Height + 4),     
  42.         pinSize.Width,     
  43.         pinSize.Height);     
  44.         this.textBounds = new Rectangle(     
  45.         pinSize.Width + 10,     
  46.         5,     
  47.         this.ClientRectangle.Width - (pinSize.Width + 10),     
  48.         20);     
  49.     }     
  50.     this.Invalidate();     
  51.   }     
  52.   get    
  53.   {     
  54.     return align;     
  55.   }     
  56. }    

由于 Pin 對(duì)象不會(huì)提供很好的用戶(hù)交互或可自定義性,所以引腳的核心功能是我們將重寫(xiě)的繪圖例程 OnDraw,重寫(xiě)該例程是為了可以由我們來(lái)繪制整個(gè)引腳。

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

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

下一步,我們使用 FillEllipse 來(lái)繪制所有實(shí)際的引腳,但 PinNumber=1 時(shí)除外,這時(shí)使用 FillRectangle 繪制引腳。通過(guò)繪制在矩形 (pinBounds) 中而不是控件的邊界上,我們能夠在創(chuàng)建引腳時(shí)設(shè)置引腳的位置(左側(cè)或右側(cè)),并且從這一點(diǎn)開(kāi)始,我們可以在不用關(guān)心引腳的位置的情況下進(jìn)行繪制。

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

我們使用與繪制引腳時(shí)類(lèi)似的策略來(lái)繪制文本,但這次我們必須計(jì)算水平和垂直偏移量,因?yàn)樵?Microsoft .NET 壓縮框架中,DrawText 方法不允許有 TextAlign 參數(shù)。

最終,我們通過(guò)調(diào)用 Dispose 方法清理我們手動(dòng)使用的 Brush 對(duì)象。

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

清單 2. OnDraw() 方法

  1.  protected override void OnPaint(PaintEventArgs pe)  
  2. {  
  3.   Brush b;  
  4.         // determine the Pin color  
  5.   if(this.Enabled)  
  6.   {  
  7.     if(type == PinType.Digital)  
  8.     {  
  9.       // digital pins have different on/off color  
  10.       b = new System.Drawing.SolidBrush(  
  11.       this.Value == 0 ? (digitalOffColor) : (digitalOnColor));  
  12.     }  
  13.     else 
  14.     {  
  15.       // analog pin  
  16.       b = new System.Drawing.SolidBrush(analogColor);  
  17.     }  
  18.   }  
  19.   else 
  20.   {  
  21.     // disabled pin  
  22.     b = new System.Drawing.SolidBrush(disabledColor);  
  23.   }  
  24.   // draw the pin  
  25.   if(this.PinNumber == 1)  
  26.     pe.Graphics.FillRectangle(b, pinBounds);  
  27.   else 
  28.     pe.Graphics.FillEllipse(b, pinBounds);  
  29.   // draw a border Rectangle around the pin  
  30.   pe.Graphics.DrawRectangle(new Pen(Color.Black), pinBorder);  
  31.   // draw the text centered in the text bound  
  32.   string drawstring;  
  33.   // are we showing the Text or Value?  
  34.   if(showValue)  
  35.     drawstring = Convert.ToString(this.Value);  
  36.   else 
  37.     drawstring = this.Text;  
  38.   // determine the actual string size  
  39.   SizeF fs = pe.Graphics.MeasureString(  
  40.         drawstring,  
  41.         new Font(FontFamily.GenericMonospace, 8f,  
  42.                  FontStyle.Regular));  
  43.   // draw the string  
  44.   pe.Graphics.DrawString(  
  45.       drawstring,  
  46.       new Font(FontFamily.GenericMonospace, 8f,  
  47.       FontStyle.Regular),  
  48.       new SolidBrush((showValue ? analogColor : Color.Black)),  
  49.       textBounds.X + (textBounds.Width - fs.ToSize().Width) / 2,  
  50.       textBounds.Y + (textBounds.Height - fs.ToSize().Height) /  
  51.                  2);  
  52.   // clean up the Brush  
  53.   b.Dispose();  
  54.   }  
  55. }  

構(gòu)建 Pin 類(lèi)的***一步是添加 Click 處理程序。對(duì)于我們的 Pin 類(lèi)來(lái)說(shuō),我們將使用自定義的 EventArg,以便可以向事件處理程序傳遞引腳的文本和編號(hào)。要?jiǎng)?chuàng)建自定義的 EventArg,我們只是創(chuàng)建了一個(gè)從 EventArgs 類(lèi)派生的類(lèi):

  1. public class PinClickEventArgs : EventArgs  
  2. {  
  3.   // a PinClick passes the Pin Number and the Pin's Text  
  4.   public int number;  
  5.   public string text;  
  6.   public PinClickEventArgs(int PinNumber, string PinText)  
  7.   {  
  8.     number = PinNumber;  
  9.     text = PinText;  
  10.   }  
  11. }  

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

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

現(xiàn)在,我們需要添加代碼來(lái)確定什么時(shí)候發(fā)生單擊,然后引發(fā)事件。對(duì)于我們的 Pin 類(lèi),當(dāng)引腳的邊框矩形內(nèi)部發(fā)生 MouseDown 和 MouseUp 事件時(shí)即為一個(gè)邏輯上的單擊 - 這樣,如果用戶(hù)單擊引腳的文本部分,則不會(huì)觸發(fā) Click 事件,但如果點(diǎn)擊表示實(shí)際引腳的區(qū)域,則觸發(fā)該事件。

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

  1. public event PinClickHandler PinClick;   

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

  1. bool midClick;  

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

清單 3. 用于實(shí)現(xiàn) PinClick 事件的事件處理程序

  1. private void PinMouseDown(object sender, MouseEventArgs e)     
  2. {     
  3.   if(!this.Enabled)     
  4.     return;     
  5.   // if the user clicked in the "pin" rectangle, start a click process     
  6.   midClick = pinBorder.Contains(e.X, e.Y);     
  7. }     
  8. private void PinMouseUp(object sender, MouseEventArgs e)     
  9. {     
  10.   // if we had a mousedown and then up inside the "pin" rectangle,     
  11.   // fire a click     
  12.   if((midClick) && (pinBorder.Contains(e.X, e.Y)))     
  13.   {     
  14.     if(PinClick != null)     
  15.       PinClick(thisnew PinClickEventArgs(     
  16.                this.PinNumber, this.Text));     
  17.   }     
  18. }    

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

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

清單 4. Pins 類(lèi)

  1. public class Pins : CollectionBase  
  2. {  
  3.   public void Add(Pin PinToAdd)  
  4.   {  
  5.     List.Add(PinToAdd);  
  6.   }  
  7.   public void Remove(Pin PinToRemove)  
  8.   {  
  9.     List.Remove(PinToRemove);  
  10.   }  
  11.   // Indexer for Pins  
  12.   public Pin this[byte Index]  
  13.   {  
  14.     get 
  15.     {  
  16.       return (Pin)List[Index];  
  17.     }  
  18.     set 
  19.     {  
  20.       List[Index] = value;  
  21.     }  
  22.   }  
  23.   public Pins(){}  
  24. }  

實(shí)現(xiàn) Connector 類(lèi)既然我們已經(jīng)獲得了 Pins 類(lèi),我們現(xiàn)在需要構(gòu)建 Connector 類(lèi),該類(lèi)將是一個(gè)簡(jiǎn)單的包裝類(lèi),這個(gè)包裝類(lèi)包含 Pins 類(lèi),并在每個(gè)引腳和連接器容器之間封送 PinClick 事件,而且它有一個(gè)表示連接器上的引腳數(shù)的構(gòu)造函數(shù)。清單 5 顯示了完整的 Connector 類(lèi)。

清單 5. Connector 類(lèi)

  1. public class Connector : System.Windows.Forms.Control  
  2. {  
  3.   public event PinClickHandler PinClick;  
  4.   protected Pins pins;  
  5.   byte pincount;  
  6.   public Connector(byte TotalPins)  
  7.   {  
  8.     pins = new Pins();  
  9.     pincount = TotalPins;  
  10.     InitializeComponent();  
  11.   }  
  12.   private void InitializeComponent()  
  13.   {  
  14.     for(int i = 0 ; i <  pincount ; i++)  
  15.     {  
  16.       Pin p = new Pin(PinType.Digital,  
  17.             (PinAlignment)((i + 1) % 2), 0);  
  18.       p.PinClick += new PinClickHandler(OnPinClick);  
  19.       p.PinNumber = i + 1;  
  20.       p.Text = Convert.ToString(i);  
  21.       p.Top = (i / 2) * p.Height;  
  22.       p.Left = (i % 2) * p.Width;  
  23.       this.Pins.Add(p);  
  24.       this.Controls.Add(p);  
  25.     }  
  26.     this.Width = Pins[0].Width * 2;  
  27.     this.Height = Pins[0].Height * this.Pins.Count / 2;  
  28.   }  
  29.   public Pins Pins  
  30.   {  
  31.     set 
  32.     {  
  33.       pins = value;  
  34.     }  
  35.     get 
  36.     {  
  37.       return pins;  
  38.     }  
  39.   }  
  40.   private void OnPinClick(Pin sender, PinClickEventArgs e)  
  41.   {  
  42.     // pass on the event  
  43.     if(PinClick != null)  
  44.     {  
  45.       PinClick(sender, e);  
  46.       if(sender.Type == PinType.Digital)  
  47.         sender.Value = sender.Value == 0 ? 1 : 0;  
  48.       else 
  49.         sender.DisplayValue = !sender.DisplayValue;  
  50.     }  
  51.   }  
  52.   protected override void Dispose( bool disposing )  
  53.   {  
  54.     base.Dispose( disposing );  
  55.   }  
  56. }  

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

C#自定義控件:構(gòu)建自定義連接器

Connector 類(lèi)本身很簡(jiǎn)單,它不會(huì)修改任何默認(rèn)的引腳設(shè)置。但是,我們現(xiàn)在可以通過(guò)從 Connector 類(lèi)派生新的類(lèi),從而構(gòu)建一個(gè)自定義連接器,并修改單個(gè)引腳(例如,使某些引腳成為模擬引腳,或?qū)⑵浣茫?/P>

在示例應(yīng)用程序中,我為 Applied Data Systems 的 Graphics Master 板創(chuàng)建了兩個(gè)連接器,一個(gè)用于 J2,一個(gè)用于 J7。構(gòu)造函數(shù)基于連接器設(shè)置引腳的類(lèi)型以及引腳的文本。圖 2 是窗體上有 J2 和 J7 的示例應(yīng)用程序的屏幕快照。

使用兩個(gè) Connector 對(duì)象的窗體 

圖 3. 使用兩個(gè) Connector 對(duì)象的窗體

【編輯推薦】

  1. 淺談C#中構(gòu)造函數(shù)和成員函數(shù)
  2. C#函數(shù)的參數(shù)返回結(jié)構(gòu)數(shù)組
  3. 概述ASP.NET中的NGWS Runtime
  4. C#函數(shù)與JavaScript函數(shù)
  5. 詳解C# Object.Equals函數(shù)
責(zé)任編輯:book05 來(lái)源: hi.baidu
相關(guān)推薦

2009-08-03 13:34:06

自定義C#控件

2009-08-03 13:39:46

C#自定義用戶(hù)控件

2009-09-11 11:04:23

C# WinForm自

2024-09-11 14:46:48

C#旋轉(zhuǎn)按鈕

2009-08-05 17:03:37

C#自定義控件

2009-08-03 14:42:50

C#自定義控件

2009-08-04 13:23:40

C# 自定義控件dll

2009-06-08 20:13:36

Eclipse自定義控

2009-08-04 09:56:46

C#事件處理自定義事件

2009-08-04 08:58:01

C#自定義特性

2009-08-04 12:56:51

C#自定義事件

2009-08-28 17:45:19

C#自定義數(shù)據(jù)

2009-09-03 15:46:57

C#自定義事件

2009-08-17 17:24:02

C#自定義消息框

2009-08-04 13:07:46

C#自定義快捷鍵

2009-08-04 13:31:35

C#自定義事件

2009-08-03 13:32:38

C#自定義組件

2009-07-28 09:32:41

ASP.NET自定義控

2009-08-12 14:53:50

C#類(lèi)型轉(zhuǎn)換函數(shù)

2009-08-04 12:40:34

c#自定義事件
點(diǎn)贊
收藏

51CTO技術(shù)棧公眾號(hào)