溫馨提示×

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

密碼登錄×
登錄注冊(cè)×
其他方式登錄
點(diǎn)擊 登錄注冊(cè) 即表示同意《億速云用戶服務(wù)條款》

WinForm怎么構(gòu)建通用的速選組件

發(fā)布時(shí)間:2021-06-17 15:42:11 來源:億速云 閱讀:133 作者:chen 欄目:編程語言

本篇內(nèi)容介紹了“WinForm怎么構(gòu)建通用的速選組件”的有關(guān)知識(shí),在實(shí)際案例的操作過程中,不少人都會(huì)遇到這樣的困境,接下來就讓小編帶領(lǐng)大家學(xué)習(xí)一下如何處理這些情況吧!希望大家仔細(xì)閱讀,能夠?qū)W有所成!

對(duì)于WinForm組件,大家并不陌生。在這里我們將為大家講解WinForm通用速選組件的構(gòu)建,這也是通往WinForm開發(fā)的必經(jīng)之路。

用戶界面中,需要用戶進(jìn)行多項(xiàng)選擇時(shí),我們通常會(huì)提供一組快速選擇(以下簡(jiǎn)稱速選)按鈕:全選、反選、清空,以方便用戶操作。本文章將會(huì)構(gòu)建一個(gè)通用速選組件來簡(jiǎn)化操作,使用之后,您不需要編寫任何代碼,只需設(shè)置兩個(gè)屬性便可讓一個(gè)控件擁有速選的功能。

WinForm中常見的幾種多選形式如下圖:

WinForm怎么構(gòu)建通用的速選組件

圖1

我們暫且將用于顯示選項(xiàng)的控件叫做“選項(xiàng)控件”,全選、反選、清空叫做“速選按鈕”。

四種形式采用了不同的控件用作選項(xiàng)控件、速選按鈕:

 選項(xiàng)控件速選按鈕
形式一CheckedListBoxLabel
形式二CheckBoxLinkLabel
形式三TreeViewButton
形式四DataGridViewPictureBox

實(shí)際使用中還可能會(huì)有其它形式的選項(xiàng)控件和速選按鈕,根據(jù)使用場(chǎng)合不同,選項(xiàng)控件和速選按鈕可以任意組合。這給我們編程帶來了麻煩,選項(xiàng)控件沒有統(tǒng)一的訪問接口,換一個(gè)選項(xiàng)控件就要編寫不同的選擇代碼。

想要將全選、反選、清空的選擇邏輯提取出來還真不容易。于是很多程序員就選擇了針對(duì)實(shí)際應(yīng)用的組合(如形式一,CheckedListBox + Label)進(jìn)行直接編碼。這樣導(dǎo)致大量相似的代碼充斥在項(xiàng)目之中,會(huì)帶來以下問題:

  1. 重復(fù)的編碼、調(diào)試、測(cè)試(主要是界面)工作;

  2. 一旦選項(xiàng)控件發(fā)生改變,就必須修改代碼,修改后還要測(cè)試;(可能性比較大,可能客戶不喜歡形式一,非要你修改成形式二)

這樣的直接編碼實(shí)際上已經(jīng)違反了DRY原則,我們應(yīng)該糾正。

面向?qū)ο笠笪覀兎庋b變化,我們這里不變的是速選的邏輯,變化的是選項(xiàng)控件和速選按鈕,變化是兩個(gè)方向的,有點(diǎn)接近橋模式的應(yīng)用場(chǎng)景了。不過我對(duì)設(shè)計(jì)模式了解不深,不敢冒用,而且感覺這里速選按鈕的變化是比較簡(jiǎn)單的,至少它們都有一個(gè)Click事件,也可以認(rèn)為是不變的。

我們采用另外一種途徑,.Net其實(shí)已經(jīng)給我們提供了一種擴(kuò)展控件功能的方式(也正體現(xiàn)了面向?qū)ο蟮腛CP原則),可以讓我們給控件賦予額外的功能。我們來看一個(gè)重要的接口:IExtenderProvider 接口,位于System.ComponentModel命名空間下。實(shí)現(xiàn)了這個(gè)接口的組件有ToolTip、ErrorProvider等,ToolTip、ErrorProvider這兩個(gè)組件可以向其它組件(控件是組件的一種)提供額外的功能,ToolStip能讓其它控件在用戶鼠標(biāo)懸停時(shí)彈出一個(gè)小框顯示一些提示信息,ErrorProvider則能讓控件顯式錯(cuò)誤信息。

我們要做的就是創(chuàng)建一個(gè)新的組件,實(shí)現(xiàn)IExtenderProvider接口,向控件(Button、Label等)提供速選的功能。這個(gè)組件我已經(jīng)完成了,名字叫FastSelect,先不考慮實(shí)現(xiàn)原理、如何實(shí)現(xiàn),我們先看下如何使用吧:

FastSelect是一個(gè)組件,會(huì)自動(dòng)顯示在工具箱中,將其拖入窗體,將會(huì)顯示在設(shè)計(jì)器下方。

WinForm怎么構(gòu)建通用的速選組件

圖2

選中全選按鈕(label1),屬性顯示窗口如下圖:

WinForm怎么構(gòu)建通用的速選組件

圖3

分組中出現(xiàn)了一個(gè)新的分組:速選,其中有如上圖兩個(gè)屬性,***個(gè)屬性用于選擇選項(xiàng)控件,第二個(gè)屬性用于確定選擇方式(全選還是清空)。設(shè)置兩個(gè)屬性的值如上圖,完成后label1就可以全選分類中的所有選項(xiàng)了。

簡(jiǎn)單說來,只需要向窗體置入一個(gè)控件(Button、Label、LinkLabel、Picture),簡(jiǎn)單設(shè)置兩個(gè)屬性,這個(gè)控件就自動(dòng)具有了速選功能,不需要任何代碼。當(dāng)然得借助FastSelect組件。

這么神奇,是如何實(shí)現(xiàn)的呢?要從IExtenderProvider接口說起,這個(gè)接口可以向其他組件提供屬性,如上圖中的兩個(gè)屬性。有這里有兩點(diǎn)要說明一下:

  1. 向其它組件提供屬性,這個(gè)可以限定,比如僅只向Button提供。

  2. 提供屬性并不是真正給其他組件加上新的屬性,只是在WinForm設(shè)計(jì)時(shí),在PropertyGrid中顯示額外屬性(后面會(huì)詳說)。

我們來看下FastSelect是如何實(shí)現(xiàn)的:

public enum SelectionType    {        清空,        反選,        全選,    }     [ProvideProperty("SelectionSource", typeof(Control))]    [ProvideProperty("SelectionType", typeof(Control))]    public partial class FastSelect : Component, IExtenderProvider    {             public bool CanExtend(object extendee)        {            if (extendee == null) return false;           if (extendee is Button || extendee is Label || extendee is PictureBox) return true;           return false;        }        [Category("速選"), Description("速選源控件"), Localizable(true)]        public Control GetSelectionSource(Control control)        {            ...        }        public void SetSelectionSource(Control control, Control selectionSource)        {            ...        }          [Category("速選"), Description("速選方式"), DefaultValue(SelectionType.清空), Localizable(true)]        public SelectionType GetSelectionType(Control control)        {                  }       public void SetSelectionType(Control control, SelectionType selectionType)       {           ...      }       ...        }

SelectionType枚舉不必多說,我們來看FastSelect,它繼承至Component,實(shí)現(xiàn)了IExtenderProvider接口。

CanExtend是IExtenderProvider接口的***成員,它用來標(biāo)識(shí)可以給那些組件進(jìn)行擴(kuò)展,上面的代碼中我們限定了只可以給Button、Label、PictureBox進(jìn)行擴(kuò)展,也就是說其它類型的控件在屬性窗口中是看不到速選屬性的。CanExtend中沒有LinkLabel,是因?yàn)長(zhǎng)inkLabel是Label的子類,Label有的它也會(huì)自動(dòng)擁有。

Get(Set) SelectionSource、Get(Set)SelectionType有點(diǎn)類似屬性的get/set吧,只不過多了一個(gè)參數(shù)(***個(gè)參數(shù)control),傳入這個(gè)參數(shù)的是要進(jìn)行屬性擴(kuò)展的控件,還是讓我們看一下WinForm生成的代碼吧(在Form1.generated.cs中)

this.fastSelect.SetSelectionSource(this.label1, this.categoriesListBox);   this.fastSelect.SetSelectionType(this.label1, SelectionType.全選);

對(duì)照?qǐng)D三,應(yīng)該明白“提供屬性”的真正含義了吧。

我們?cè)賮砜词侨绾螌?shí)現(xiàn)選擇的,先看代碼片段:

public partial class FastSelect : Component, IExtenderProvider      {          private Dictionary sourceControlsDict;          private Dictionary typeDict;         public void SetSelectionSource(Control control, Control selectionSource)        {                           sourceControlsDict.Add(control, selectionSource);               control.Click += new EventHandler(control_Click);                      }          public void SetSelectionType(Control control, SelectionType selectionType)        {                         typeDict.Add(control, selectionType);                       }           void control_Click(object sender, EventArgs e)           {              Control control = sender as Control;             Control selectionSource = sourceControlsDict[control];              SelectionType selectType = typeDict[control];                if (selectionSource is DataGridView)              {                   DataGridView dataGridView = selectionSource as DataGridView;                   foreach (DataGridViewRow row in dataGridView.Rows)                       row.Selected = ChangeSelected(row.Selected, selectType);               }                         }             private bool ChangeSelected(bool isSelected, SelectionType type)           {             if (type == SelectionType.清空) return false;              else if (type == SelectionType.全選) return true;             else if (type == SelectionType.反選) return !isSelected;              else throw new NotImplementedException();           }                 }

一個(gè)窗體上只需要一個(gè)FastSelect組件,但它要為其它多個(gè)組件提供屬性,我們這里使用Dictionary保存這些屬性。

設(shè)置控件SelectionSource屬性時(shí),其實(shí)是調(diào)用了SetSelectionSource方法,其中我們?yōu)榭丶?cè)了Click事件,control_Click中根據(jù)不同的選項(xiàng)控件的類型(DataGridView、CheckedListBox等)和選擇類型進(jìn)行相應(yīng)的處理。這樣應(yīng)該明白了吧。

“WinForm怎么構(gòu)建通用的速選組件”的內(nèi)容就介紹到這里了,感謝大家的閱讀。如果想了解更多行業(yè)相關(guān)的知識(shí)可以關(guān)注億速云網(wǎng)站,小編將為大家輸出更多高質(zhì)量的實(shí)用文章!

向AI問一下細(xì)節(jié)

免責(zé)聲明:本站發(fā)布的內(nèi)容(圖片、視頻和文字)以原創(chuàng)、轉(zhuǎn)載和分享為主,文章觀點(diǎn)不代表本網(wǎng)站立場(chǎng),如果涉及侵權(quán)請(qǐng)聯(lián)系站長(zhǎng)郵箱:is@yisu.com進(jìn)行舉報(bào),并提供相關(guān)證據(jù),一經(jīng)查實(shí),將立刻刪除涉嫌侵權(quán)內(nèi)容。

AI