一、 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, DataGridViewCellStylecellStyle, 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/
下一講 將介紹如何設計一個單元格內容格式化器,輕松實現按內容顯示顏色、禁用按鈕等。