開源DataGridView擴展(2) 自定義的Button列


r1

r2

一、 DataGridView自帶的Button列的缺點

1. 按鈕大小不能控制。

2. 按鈕文本要么是統一要么就跟單元格內容一致,不能根據具體內容划分幾種類型。

3. 按鈕的啟用/禁用不容易按照內容來自動綁定。

4. 按鈕的顯示/隱藏也不容易按照內容自動綁定。

5. 按鈕的點擊事件不能直接拋出,只能靠捕獲CellContentClick事件。

6. 一列不能有多個按鈕。

二、 DataGridViewEx中是否解決這些問題

1. 如以上圖中所示,使用重繪機制,在定義實現的Button列中的可以實現按鈕的大小固定,不隨單元格改變。並且在Column中可以設置統一的 

    的按鈕大小,但是也可以分別設置每一個按鈕的大小,既大小可以不相同。

2. 自定義表格中使用Column中的統一默認文本,同時也提供對每一個單元格中的按鈕進行單獨的設置,這樣就可以結合后面的單元格內容格式化

    器來實現不同類型的內容顯示不同的按鈕了。

3. 在自定義的Button列中支持單個按鈕的啟用/禁用、顯示/隱藏。這個也可以通過下一講中的單元格內容格式化器來實現綁定。

4. 在自定義的Button列中單獨對按鈕的點擊事件直接拋出給DataGridVieEx層,由DataGridViewEx的CellButtonClicked事件綁定即可,這樣就  

    不用再CellClick中綁定,並且還可能出現點擊單元格也響應了事件的問題了,這個事件如上面的第二個圖。

5. 對於同一列多個按鈕的情況,暫時實現,如果以后又可能再繼續要講。

 

    通過這些,其實我們要掌握一個Buttonlie重繪的一個思想:根據我們的需求,更多的東西應該轉向按鈕本身而不是這一單元格。

三、 DataGridViewEx中的Button列的實現

    就其實現來說,和上一個CheckBox列差不多,Button列主要擴展了兩個類:DataGridViewButtonColumnEx和DataGridViewButtonCellEx,

1. 在DataGridViewButtonColumnEx中將CellTemplate設置為DataGridViewButtonCellEx實例:5

        public DataGridViewButtonColumnEx()
            : base()
        {
            this.CellTemplate = new DataGridViewButtonCellEx();
        }
2. 在DataGridViewButtonCellEx中定義一些需要有用的屬性,主用用於按鈕,把屬性的用途從Cell轉為Button:
        private bool m_enabled = true;
        [Category("Jonson Design"), Browsable(true), Localizable(true), Description("是否可用")]
        public bool Enabled
        {
            get { return m_enabled; }
            set { m_enabled = value; }
        }

        /// <summary>
        /// 這里按鈕的可見進行重寫,原有的是從column中統一設置,
        /// 通過此屬性可以單獨設置是否可見
        /// </summary>
        private bool m_visible = true;
        [Category("Jonson Design"), Browsable(true), Localizable(true), Description("是否可見")]
        public new bool Visible
        {
            get { return m_visible; }
            set { m_visible = value; }
        }

        /// <summary>
        /// 如果按鈕文本沒有單獨設置的話,將使用column中設置的文本
        /// </summary>
        private string m_text = string.Empty;
        [Category("Jonson Design"), Browsable(true), Localizable(true), Description("按鈕文本")]
        public string Text
        {
            get
            {
                if (string.IsNullOrEmpty(m_text))
                    m_text = this.OwningColumnEx.ButtonText;
                return m_text;
            }
            set
            {
                m_text = value;
            }
        }
 
3. 針對按鈕在鼠標的不同作用下顯示不同樣式進行處理,要處理這些鼠標的事件:
     protected override void OnMouseMove(DataGridViewCellMouseEventArgs e)
        {
            base.OnMouseMove(e);
            if (IsInRegion(e.Location, e.ColumnIndex, e.RowIndex))
            {
                this.m_curBtnState = PushButtonState.Hot;
            }
            else
            {
                this.m_curBtnState = PushButtonState.Normal;
            }
            this.DataGridView.InvalidateCell(this);
        }

        protected override void OnMouseLeave(int rowIndex)
        {
            base.OnMouseLeave(rowIndex);
            this.m_curBtnState = PushButtonState.Normal;
            this.DataGridView.InvalidateCell(this);
        }

        protected override void OnMouseDown(DataGridViewCellMouseEventArgs e)
        {
            base.OnMouseDown(e);
            if (IsInRegion(e.Location, e.ColumnIndex, e.RowIndex))
            {
                this.m_curBtnState = PushButtonState.Pressed;
            }
            else
            {
                this.m_curBtnState = PushButtonState.Normal;
            }
            this.DataGridView.InvalidateCell(this);
        }

 

 

4. 繪制按鈕,在Paint方法中將按鈕按照設定的大小、各種屬性以及當前的狀態進行繪制:

 

        protected override void Paint(Graphics graphics, Rectangle clipBounds, Rectangle cellBounds, int rowIndex,    
           DataGridViewElementStates elementState, object value, object formattedValue, string errorText, DataGridViewCellStyle 
           cellStyle, DataGridViewAdvancedBorderStyle advancedBorderStyle, DataGridViewPaintParts paintParts)
        {
            //
            // 此段代碼主要解決xp下,如果鼠標默認在按鈕列上,按鈕的默認繪制樣式問題
            //
            if (this.m_firstDraw)
            {
                this.m_firstDraw = false;
                this.m_curBtnState = this.Enabled ? PushButtonState.Normal : PushButtonState.Disabled;
            }
            // 是否需要重繪單元格的背景顏色
            m_brushCellBack = this.DataGridView.SelectedCells.Contains(this) ?
                new SolidBrush(cellStyle.SelectionBackColor) : new SolidBrush(cellStyle.BackColor);
            graphics.FillRectangle(m_brushCellBack, cellBounds.X, cellBounds.Y, cellBounds.Width, cellBounds.Height);

            //計算button的區域
            m_buttonRegion = RectangleCommon.GetSmallRectOfRectangle(cellBounds, this.Size, out this.m_absBtnRegion);

            //繪制按鈕
            if (m_enabled)
                this.InternalDrawButton(graphics, m_buttonRegion, m_curBtnState, Text);
            else
                this.InternalDrawButton(graphics, m_buttonRegion, PushButtonState.Disabled, Text);

            // 填充單元格的邊框
            base.PaintBorder(graphics, clipBounds, cellBounds, cellStyle, advancedBorderStyle);
        }

        protected void InternalDrawButton(Graphics graphics, Rectangle bounds, PushButtonState buttonState, string buttonText)
        {
            //如果是隱藏的,不繪制
            if (!m_visible) return;

            Color buttonTextColor = SystemColors.ControlText;
            if (buttonState == PushButtonState.Disabled)
                buttonTextColor = SystemColors.GrayText;

            ButtonRenderer.DrawButton(graphics, bounds, buttonState);
            if (buttonText != null)
                TextRenderer.DrawText(graphics, buttonText, this.DataGridView.Font, bounds, buttonTextColor);
        }

四、 Demo程序和開源源碼

         上一篇    :開源DataGridView擴展(1) 擴展支持全選的CheckBox列。

         Demo下載  :點擊這里

         源碼下載   :http://sourceforge.net/p/datagridviewex/code-0/3/tree/trunk/DataGridViewEx/

 

下一講  將介紹如何設計一個單元格內容格式化器,輕松實現按內容顯示顏色、禁用按鈕等。


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM