1. 程式人生 > >.net WinForm使用者控制元件開發--(3)可多選的下拉列表框

.net WinForm使用者控制元件開發--(3)可多選的下拉列表框

      這一節給大家演示一個具有多選功能的下拉列表框,其實就是一個文字框和checkboxlist組合實現的使用者控制元件,換個角度來實現自定義控制元件。

先來看下效果圖吧,我會分幾個步驟來具體講解這個文字框的實現。

                                        

    1.介面實現

     我們先來看下介面效果怎樣實現,然後再講解具體的功能性實現。

      先建立一個使用者控制元件,當然是繼承UserControl類,這個介面需要用到以下控制元件來實現

     下拉按鈕:是一個button控制元件

     文字框:顯示選中的內容,

     多選列表框: checkboxlist

     全選/取消:是兩個LABEL控制元件

      右下角的黑三角:是一個LABEL控制元件,可實現拉長下拉列表框.

      窗體:點選下拉按鈕,實際是彈出一個窗體,下拉列表框中的控制元件都在這個窗體中顯示

    首先看下下拉按鈕的實現

/// <summary>
    /// 重寫BUTTON
    /// </summary>
    public class ButtonS : Button
    {
        public ButtonS()
        {
            //防止重繪控制元件出現閃爍
            this.SetStyle(ControlStyles.UserPaint, true);
            this.SetStyle(ControlStyles.OptimizedDoubleBuffer, true);
            this.SetStyle(ControlStyles.AllPaintingInWmPaint, true);
        }
        ButtonState state;
        //當按鈕被按下
        protected override void OnMouseDown(MouseEventArgs mevent)
        {
            state = ButtonState.Pushed;
            base.OnMouseDown(mevent);
        }

        //當按鈕被釋放
        protected override void OnMouseUp(MouseEventArgs mevent)
        {
            state = ButtonState.Normal;
            base.OnMouseUp(mevent);
        }

        protected override void OnPaint(PaintEventArgs pevent)
        {
            base.OnPaint(pevent);
            System.Windows.Forms.ControlPaint.DrawComboButton(pevent.Graphics, 0, 0, this.Width, this.Height, state);
        }
    }


   接下來再看下具有拉動功能的LABEL

/// <summary>
    /// 重寫LABEL
    /// </summary>
    public class LabelS : Label
    {
        public LabelS()
        {
            //控制元件繪製的時候減少閃爍
            this.SetStyle(ControlStyles.UserPaint, true);
            this.SetStyle(ControlStyles.OptimizedDoubleBuffer, true);
            this.SetStyle(ControlStyles.AllPaintingInWmPaint, true);
        }

        protected override void OnPaint(PaintEventArgs e)
        {
            base.OnPaint(e);
            System.Windows.Forms.ControlPaint.DrawSizeGrip(e.Graphics, Color.Black, 1, 0, this.Size.Width, this.Size.Height);
        }
    }


 接下來,我們動態用程式碼生成這些控制元件,並設定控制元件的佈局,

 現在建構函式裡生成這些控制元件,然後在使用者控制元件的ComCheckBoxList_Layout事件裡面佈局這些控制元件,程式碼如下

 /// <summary>
    /// 帶下拉框的使用者控制元件
    /// </summary>
    public partial class ComCheckBoxList : UserControl
    {
        private TextBox tbSelectedValue;
        private ButtonS btnSelect;//下拉箭頭
        private LabelS lbGrip;//此LABEL用於設定可以拖動下拉窗體變化

        private CheckedListBox checkListBox;
        private Label lbSelectAll;//全選
        private Label lbSelectNo;//取消

        private Form frmCheckList;

        private Panel pnlBack;
        private Panel pnlCheck;

        private System.Drawing.Point DragOffset; //用於記錄窗體大小變化的位置
        public ComCheckBoxList()
        {
            InitializeComponent();
            this.Name = "comBoxCheckBoxList";
            this.Layout+=new LayoutEventHandler(ComCheckBoxList_Layout);

            //生成控制元件
            tbSelectedValue = new TextBox();
            tbSelectedValue.ReadOnly = true;
            tbSelectedValue.BorderStyle = BorderStyle.None;

            //下拉箭頭
            this.btnSelect = new ButtonS();
            btnSelect.FlatStyle = FlatStyle.Flat;
            btnSelect.Click+=new EventHandler(btnSelect_Click);

            //全選
            this.lbSelectAll = new Label();
            lbSelectAll.BackColor = Color.Transparent;
            lbSelectAll.Text = "全選";
            lbSelectAll.Size = new Size(40, 20);
            lbSelectAll.ForeColor = Color.Blue;
            lbSelectAll.Cursor = Cursors.Hand ;
            lbSelectAll.TextAlign = ContentAlignment.MiddleCenter;
            lbSelectAll.Click+=new EventHandler(lbSelectAll_Click);

            //取消
            lbSelectNo = new Label();
            lbSelectNo.BackColor = Color.Transparent;
            lbSelectNo.Text = "取消";
            lbSelectNo.Size = new Size(40, 20);
            lbSelectNo.ForeColor = Color.Blue;
            lbSelectNo.Cursor = Cursors.Hand;
            lbSelectNo.TextAlign = ContentAlignment.MiddleCenter;
            lbSelectNo.Click+=new EventHandler(lbSelectNo_Click);

            //生成checkboxlist
            this.checkListBox = new CheckedListBox();
            checkListBox.BorderStyle = BorderStyle.None;
            checkListBox.Location = new Point(0,0);
            checkListBox.CheckOnClick = true;
            checkListBox.ScrollAlwaysVisible = true;
            checkListBox.LostFocus +=new EventHandler(checkListBox_LostFocus);
            checkListBox.ItemCheck+=new ItemCheckEventHandler(checkListBox_ItemCheck);

            //窗體
            frmCheckList = new Form();
            frmCheckList.FormBorderStyle = FormBorderStyle.None;
            frmCheckList.StartPosition = FormStartPosition.Manual;
            frmCheckList.BackColor = SystemColors.Control;
            frmCheckList.ShowInTaskbar = false;

            //可拖動窗體大小變化的LABEL
            lbGrip = new LabelS();
            lbGrip.Size = new Size(9,18);
            lbGrip.BackColor = Color.Transparent;
            lbGrip.Cursor = Cursors.SizeNWSE;
            lbGrip.MouseDown+=new MouseEventHandler(lbGrip_MouseDown);
            lbGrip.MouseMove+=new MouseEventHandler(lbGrip_MouseMove);

            //panel
            pnlBack = new Panel();
            pnlBack.BorderStyle = BorderStyle.Fixed3D;
            pnlBack.BackColor = Color.White;
            pnlBack.AutoScroll = false;

            //
            pnlCheck = new Panel();
            pnlCheck.BorderStyle = BorderStyle.FixedSingle;
            pnlCheck.BackColor = Color.White; ;

            SetStyle(ControlStyles.OptimizedDoubleBuffer, true);
            SetStyle(ControlStyles.ResizeRedraw, true);

            pnlBack.Controls.Add(tbSelectedValue);
            pnlBack.Controls.Add(btnSelect);

            this.Controls.Add(pnlBack);

            pnlCheck.Controls.Add(checkListBox);
            pnlCheck.Controls.Add(lbSelectAll);
            pnlCheck.Controls.Add(lbSelectNo);
            pnlCheck.Controls.Add(lbGrip);
            this.frmCheckList.Controls.Add(pnlCheck);

          
        }

        private void ReloationGrip()
        {

            lbGrip.Top = this.frmCheckList.Height - lbGrip.Height - 1;
            lbGrip.Left = this.frmCheckList.Width - lbGrip.Width - 1;

            lbSelectAll.Left =5;
            lbSelectAll.Top = frmCheckList.Height - lbSelectAll.Height;

            lbSelectNo.Left = 50;
            lbSelectNo.Top = frmCheckList.Height - lbSelectNo.Height;
      

        }

        #region 事件
        
      
        //佈局
        private void ComCheckBoxList_Layout(object sender,LayoutEventArgs e)
        {
            this.Height = tbSelectedValue.Height + 6;
            this.pnlBack.Size = new Size(this.Width, this.Height - 2);

            //設定按鈕的位置
            this.btnSelect.Size = new Size(16, this.Height - 6);
            btnSelect.Location = new Point(this.Width - this.btnSelect.Width - 4, 0);

            this.tbSelectedValue.Location = new Point(2, 2);
            this.tbSelectedValue.Width = this.Width - btnSelect.Width - 4;

            checkListBox.Height =150;

            //設定窗體
            this.frmCheckList.Size = new Size(this.Width,this.checkListBox.Height);
            this.pnlCheck.Size =frmCheckList.Size;
           

            this.checkListBox.Width = this.frmCheckList.Width;
            this.checkListBox.Height = this.frmCheckList.Height-lbSelectNo.Height;

            ReloationGrip();


        }
        /// <summary>
        /// 單價下拉框
        /// </summary>
        /// <param name="sender"></param>
        /// <param name="e"></param>
        public void btnSelect_Click(object sender,EventArgs e)
        {
            if (this.frmCheckList.Visible == false)
            {
                Rectangle rec = this.RectangleToScreen(this.ClientRectangle);
                this.frmCheckList.Location = new Point(rec.X, rec.Y + this.pnlBack.Height);
                this.frmCheckList.Show();
                this.frmCheckList.BringToFront();

                ReloationGrip();
            }
            else
                this.frmCheckList.Hide();
        }

        //全選事件
        private void lbSelectAll_Click(object sender, EventArgs e)
        { 
        
        }
        //取消
        private void lbSelectNo_Click(object sender,EventArgs e)
        { 
        
        }

        private void checkListBox_LostFocus(object sender, EventArgs e)
        {
            //如果滑鼠位置在下拉框按鈕的以為地方,則隱藏下拉框
            if (!this.btnSelect.RectangleToScreen(this.btnSelect.ClientRectangle).Contains(Cursor.Position))
            {
                frmCheckList.Hide();
            }
        }

        private void checkListBox_ItemCheck(object sender, ItemCheckEventArgs e)
        {

        }

        /// <summary>
        /// 滑鼠按下
        /// </summary>
        /// <param name="sender"></param>
        /// <param name="e"></param>
        private void lbGrip_MouseDown(object sender, MouseEventArgs e)
        {
            if (e.Button==MouseButtons.Left)
            {
                int offsetX = System.Math.Abs(Cursor.Position.X - frmCheckList.RectangleToScreen(this.frmCheckList.ClientRectangle).Right);
                int offsetY = System.Math.Abs(Cursor.Position.Y - frmCheckList.RectangleToScreen(this.frmCheckList.ClientRectangle).Bottom);
                this.DragOffset = new Point(offsetX, offsetY);
            }
        }

        /// <summary>
        /// 滑鼠移動
        /// </summary>
        /// <param name="sender"></param>
        /// <param name="e"></param>
        private void lbGrip_MouseMove(object sender,MouseEventArgs e)
        {
            if (e.Button==MouseButtons.Left)
            {
                //獲取拉伸長度
                int curWidth = Cursor.Position.X - frmCheckList.Location.X;
                int curHeight = Cursor.Position.Y - frmCheckList.Location.Y;
                  if (curWidth<this.Width)
	              {
		                curWidth=this.Width;
	               }

                  if (curHeight<checkListBox.Height)
	              {
		                curHeight=checkListBox.Height;
	              }
          
                this.frmCheckList.Size=new Size(this.Width,curHeight);
                this.pnlCheck.Size=frmCheckList.Size;
                this.checkListBox.Height=(this.frmCheckList.Height-lbGrip.Height)<50?50:this.frmCheckList.Height-lbGrip.Height;

               ReloationGrip();
                SetStyle(ControlStyles.OptimizedDoubleBuffer, true);
                SetStyle(ControlStyles.ResizeRedraw, true);
                SetStyle(ControlStyles.UserPaint, true);
                SetStyle(ControlStyles.AllPaintingInWmPaint, true);
                


            }
        }

        #endregion
    }


  這樣使用者控制元件的佈局以及完成,我們編譯專案,就可以拖動使用者控制元件到窗體上,看到效果了

2. 繫結和新增資料

        2.1 從資料庫中讀取資料繫結顯示

               既然可以從資料庫中讀取資料,資料來源就可以是DATATABLE,我們在這裡為使用者控制元件設定資料來源,以及繫結後,要顯示的欄位,以及對於的值欄位。

              為控制元件新增以下屬性

    /// <summary>
        /// 設定資料來源
        /// </summary>
        public object DataSource
        {
            set
            {
                this.checkListBox.DataSource = value;
            }
            get
            {
                return checkListBox.DataSource;
            }
        }
        /// <summary>
        /// 設定值
        /// </summary>
        public string ValueMember
        {
            set
            {
                checkListBox.ValueMember = value;
            }
        }
        /// <summary>
        /// 設定顯示名稱
        /// </summary>
        public string DisplayMember
        {
            set
            {
                checkListBox.DisplayMember = value;
            }
        }


          2.2 新增項

           我們也可以不繫結資料來源,為控制元件新增項,所有這裡我們要為控制元件新增一個方法,可以實現手動新增項。

  /// <summary>
        /// 新增項
        /// </summary>
        public int AddItems(object value)
        {
            checkListBox.Items.Add(value);
            return checkListBox.Items.Count;
        }


    這樣我們就為使用者控制元件實現了兩種顯示資料的方法。下面我們看看在窗體中怎樣使用這兩種方法

     在窗體上放置兩個按鈕,然後繫結資料

 private void button1_Click(object sender, EventArgs e)
        {
            //繫結資料來源
            DataTable dt = new DataTable();
            DataColumn dc1 = new DataColumn("weibo", typeof(System.String));
            dt.Columns.Add(dc1);

            DataColumn dc2 = new DataColumn("mail", typeof(System.String));
            dt.Columns.Add(dc2);

            DataColumn dc3 = new DataColumn("blog", typeof(System.String));
            dt.Columns.Add(dc3);


            for (int i = 0; i < 50; i++)
            {
                DataRow dr = dt.NewRow();
                dr[0] = "下里巴人simple";
                dr[1] = "[email protected]";
                dr[2] = "msdn" + i.ToString();
                dt.Rows.Add(dr);
            }
            comCheckBoxList1.DataSource = dt;
            comCheckBoxList1.DisplayMember = "weibo";
            comCheckBoxList1.ValueMember = "mail";
        }

        private void button2_Click(object sender, EventArgs e)
        {
            //新增項
            comCheckBoxList2.AddItems("郵箱:[email protected]");
            comCheckBoxList2.AddItems("微博:下里巴人simple");
        }

  至此,第二步驟已經完成,可以實現大部分功能了.

   3.事件處理

     這裡我們定義下全選事件,取消事件,和某項選中狀態更改時發生的事件

  //全選事件
        private void lbSelectAll_Click(object sender, EventArgs e)
        {
            for (int i = 0; i < checkListBox.Items.Count; i++)
            {
                checkListBox.SetItemChecked(i, true);
            }
            tbSelectedValue.Text ="已選擇"+checkListBox.Items.Count.ToString()+"項";
        }
        //取消
        private void lbSelectNo_Click(object sender,EventArgs e)
        {
            for (int i = 0; i < checkListBox.Items.Count; i++)
            {
                checkListBox.SetItemChecked(i, false);
            }
            tbSelectedValue.Text = "沒有選擇!";
        }


     這裡我們自定義一個選項狀態更改時發生的事件,供別人使用的時候自行處理選擇狀態更改邏輯,需要我們自定義事件

  //單擊列表項狀態更改事件
        public delegate void CheckBoxListItemClick(object sender, ItemCheckEventArgs e);
        public event CheckBoxListItemClick ItemClick;
   private void checkListBox_ItemCheck(object sender, ItemCheckEventArgs e)
        {
            ItemClick(sender, e);

           //獲取選中的數量
            int nCount = this.checkListBox.CheckedItems.Count;
            if (this.checkListBox.CheckedItems.Contains(this.checkListBox.Items[e.Index]))
            {

                if (e.NewValue != CheckState.Checked)
                {
                    nCount--;
                }
            }
            else
            {
                if (e.NewValue == CheckState.Checked)
                {
                    nCount++;
                }
            }
            tbSelectedValue.Text = "已選擇" + nCount.ToString() + "項";
       
        }
  /// <summary>
        /// 選項集合
        /// </summary>
        public CheckedListBox.ObjectCollection Items
        {
            get
            {
                return checkListBox.Items;
            }
        }

        /// <summary>
        /// 獲取選中項的文字
        /// </summary>
        /// <param name="item"></param>
        /// <returns></returns>
        public string GetItemText(object item)
        {
            return checkListBox.GetItemText(item);
        }

然後當用戶把控制元件拖放到窗體上,我們就可以使用該事件了。

  /// <summary>
        /// 獲取選中項的文字
        /// </summary>
        /// <param name="sender"></param>
        /// <param name="e"></param>
        private void comCheckBoxList1_ItemClick(object sender, ItemCheckEventArgs e)
        {
          string text=comCheckBoxList1.GetItemText(comCheckBoxList1.Items[e.Index]);
          MessageBox.Show(text);
        }


    到此,這個控制元件的基本功能已經實現完成。再看下效果圖

           

相關推薦

.net WinForm使用者控制元件開發--(3)列表

      這一節給大家演示一個具有多選功能的下拉列表框,其實就是一個文字框和checkboxlist組合實現的使用者控制元件,換個角度來實現自定義控制元件。 先來看下效果圖吧,我會分幾個步驟來具體講解這個文字框的實現。                           

搜尋列表外掛

可搜尋多選下拉列表外掛 參考:http://blog.csdn.net/xb12369/article/details/50999265 <html> <head> <title>jQuery bootstrap-sele

DevExpress Winform通用控制元件開發總結

文件購買地址:https://item.taobao.com/item.htm?id=5694774231111、該文件是本人在運用DevExpress Winform從事開發工作中彙編整理2、該售價不僅包括文件的當前版本,凡購買者,該文件的所有後續版本更新都無償提供,不再另

.NET WINFORM 常用控制元件和開源庫使用網摘彙總

datagridview     http://www.cnblogs.com/peterzb/archive/2009/05/29/1491891.html NPOI http://tonyqus.sinaapp.com/tutorial Winform 實現類似w

Android 開發:(十)初識ExpandableListView(擴充套件的列表元件)

隨便扯點兒 前幾天做iOS仿QQ,其中好友列表頁面就有下拉列表的功能,iOS做法應該比安卓稍微複雜一點,其中佈局以及一些實現方法(協議方法)都類似,不一樣的應該是動畫切換效果,安卓提供現成的元件,用原生的就可以實現。 iOS示例 http://blog.

Android自定義控制元件之仿汽車之家重新整理

關於下拉重新整理的實現原理我在上篇文章Android自定義控制元件之仿美團下拉重新整理中已經詳細介紹過了,這篇文章主要介紹錶盤的動畫實現原理 汽車之家的下拉重新整理分為三個狀態: 第一個狀態為下拉重新整理狀態(pull to refresh),在這個狀

控制元件multiselect使用小結

專案開發中,需要用到多選下拉列表外掛,由於專案前端框架採用了bootstrap,因此自然選擇了bootstrap的元件。經瞭解其有兩組外掛: 1、第一個元件是寫bootstrap table的主人公 wenzhixin 封裝的一個元件—— 筆者參考了“

angularjs 控制元件angularjs ui-select2

      angularjs ui-select2:http://jsfiddle.net/jLD42/4/(這個網站測試通過),網站內容如下:找了很多其他的網站都沒用,這個是測試通過的,需要匯入所需要的js檔案,需要的圖片:      這個如果控制元件寬度是比較窄的話

列表【安卓3

pan activity border cin left 資源 pro 內容 1.0 Spinner(下拉列表框) 方法 描述 CharSequence getPrompt () 取得提示文字 void setPrompt(CharSeque

UI標籤庫專題十一 JEECG智慧開發平臺 DictSelect 資料字典選擇

分享一下我老師大神的人工智慧教程!零基礎,通俗易懂!http://blog.csdn.net/jiangjunshow 也歡迎大家轉載本篇文章。分享知識,造福人民,實現我們中華民族偉大復興!        

選擇和輸入的列表示例

<html> <head> <meta http-equiv="Content-Type" content="text/html; charset=utf-8" /> <title>可選擇和輸入的下拉列表框</title&

MVC身份驗證.MVC過濾器.MVC6關鍵字Task,Async.前端模擬表單驗證,提交.自定義匿名集合.Edge匯出到Excel.BootstrapTree樹狀選單的全和反.bootstrap搜尋

在寫這篇部落格之前要嘮叨幾句.本人已從事開發四年有餘.從前兩年的熱情如火.到現在的麻木.總感覺要像上突破.卻又不敢輕舉妄動. 沒事就寫點基礎程式碼.指點下新人吧 1.MVC身份驗證.    有兩種方式.一個是傳統的所有控制器繼承自定義Control,然後再裡面用MVC的過濾器攔截.所以每次網站的後臺被訪問時.

選擇也可以輸入的列表

<html><head><title>TW之執行程式碼外掛--Ayin增強版</title><style type="text/css">...div,span,p,td,font{...}{font-size:9pt;}</style>

jQuery.autocomplete 輸入的選擇

1. jsp                <table class="posttable">                         <colgroup>                             <col style=

wpf控制元件開發基礎(3) -屬性系統(2)

原文: wpf控制元件開發基礎(3) -屬性系統(2)     上篇說明了屬性存在的一系列問題. 屬性預設值,可以保證屬性的有效性. 屬性驗證有效性,可以對輸入的屬性進行校驗 屬性強制回撥, 即不管屬性有無發生變化,都要做出通知. 屬性變更通知,當屬性發生變

wpf控制元件開發基礎(4) -屬性系統(3)

原文: wpf控制元件開發基礎(4) -屬性系統(3) 知識回顧 接上篇,上篇我們真正接觸到了依賴屬性的用法,以及依賴屬性的屬性元資料的用法,並且也實實在在地解決了之前第二篇提到的一系列問題.來回顧一下 屬性預設值 屬性變更通知 屬性強制回撥 本篇將繼續討論上一篇提到的問題,主題依然是

C#.net 地圖控制元件開發(十一) 地圖控制元件MapControl

地圖控制元件     地圖控制元件(MapControl)包含了地圖物件(Map),並在控制元件重繪時將繪圖的控制代碼傳遞給地圖物件,讓地圖物件可以繪製圖層集合。 地圖控制元件類         作用:主要用來繪製地圖。         類:提供地圖物件屬性,可以將使用者自

C#.net 地圖控制元件開發(八) 地圖要素Feature

地圖要素     地圖要素(Feature)是構成地圖圖層的最小單元,它包括地物的幾何形狀,符號和描述資訊。描述資訊可以做成資料表的形式儲存在圖層類中,符號也可以儲存在圖層類中作為預設的要素符號,但是為了在圖層中突出表示某個特殊的地物,所以在地圖要素中也增加了符號屬性。

淺談Winform控制元件開發(一):使用GDI+美化基礎視窗

 寫在前面: 本系列隨筆將作為我對於winform控制元件開發的心得總結,方便對一些讀者在GDI+、winform等技術方面進行一個入門級的講解,拋磚引玉。 別問為什麼不用WPF,為什麼不用QT。問就是懶,不想學。 本專案所有程式碼均開源在https://github.com/muxiang/

基於Quartz.Net的任務管理平臺開發(3) —— 任務管理平臺

.cn utility tro 完成 get blog 工具 https http 有了之前對Quartz.Net的原理的理解和配置,現在需要實現對運行任務的監控和管理,完成了任務管理平臺的開發,相關代碼已經托管GitHub: https://github.com/Vice