重写DataGridViewColumn
做个项目需要用到DataGridView,这个控件还是挺好用的,但是今天却发现无法实现自己想要的功能。主要是DataGridViewCheckBoxColumn这个列虽然是提供了复选框,但是却未能在复选框的旁边提供文本的显示。在网上搜索了一下,提供的方法很多都是弄两列,然后合并单元格,将两列合并成为了一列。不过我不太喜欢那种方式,于是就自己重写了一下DataGridViewColumn,略显简陋,只实现了最基本的功能,现在拿出来,希望各位能够提一些好的意见和见解。
首先定义一个实现了 IDataGridViewEditingControl 接口的类
class DataGridViewCheckBoxTextControl : CheckBox, IDataGridViewEditingControl { /// <summary> /// 当前所在表格 /// </summary> private DataGridView MyDataGridView { set; get; } /// <summary> /// 值是否发生更改 /// </summary> private bool ValueChanged { set; get; } /// <summary> /// 当前所在行 /// </summary> private int RowIndex { set; get; } protected override void OnCheckedChanged(EventArgs e) { ValueChanged = true; this.EditingControlDataGridView.NotifyCurrentCellDirty(true); base.OnCheckedChanged(e); } public void ApplyCellStyleToEditingControl(DataGridViewCellStyle dataGridViewCellStyle) { Font = dataGridViewCellStyle.Font; ForeColor = dataGridViewCellStyle.ForeColor; BackColor = dataGridViewCellStyle.BackColor; } public DataGridView EditingControlDataGridView { get { return MyDataGridView; } set { MyDataGridView = value; } } public object EditingControlFormattedValue { get { return GetEditingControlFormattedValue(DataGridViewDataErrorContexts.Formatting); } set { Checked = value == null ? false : (bool)value; } } public int EditingControlRowIndex { get { return RowIndex; } set { RowIndex = value; } } public bool EditingControlValueChanged { get { return ValueChanged; } set { ValueChanged = value; } } public bool EditingControlWantsInputKey(Keys keyData, bool dataGridViewWantsInputKey) { switch (keyData & Keys.KeyCode) { case Keys.LButton: return !dataGridViewWantsInputKey; } return !dataGridViewWantsInputKey; } public Cursor EditingPanelCursor { get { return Cursors.Default; } } public object GetEditingControlFormattedValue(DataGridViewDataErrorContexts context) { return this.Checked; } public void PrepareEditingControlForEdit(bool selectAll) { } public bool RepositionEditingControlOnValueChange { get { return false; } } }
其次定义重写这个列所需要的单元格
public class DataGridViewCheckBoxTextCell : DataGridViewCell { public DataGridViewCheckBoxTextCell() : base() { } private static Type defaultEditType = typeof(DataGridViewCheckBoxTextControl); private static Type defaultValueType = typeof(System.Boolean); public override Type EditType { get { return defaultEditType; } } /// <summary> /// 单元格边框颜色 /// </summary> private Color CellBorderColor { get { return Color.FromArgb(172, 168, 153); } } protected override void Paint(Graphics graphics, Rectangle clipBounds, Rectangle cellBounds, int rowIndex, DataGridViewElementStates cellState, object value, object formattedValue, string errorText, DataGridViewCellStyle cellStyle, DataGridViewAdvancedBorderStyle advancedBorderStyle, DataGridViewPaintParts paintParts) { var check = (Boolean)value; if (paintParts == DataGridViewPaintParts.Background || paintParts == DataGridViewPaintParts.All) { graphics.FillRectangle(new SolidBrush(cellStyle.BackColor), cellBounds); } if (paintParts == DataGridViewPaintParts.Border || paintParts == DataGridViewPaintParts.All) { graphics.DrawRectangle(new Pen(CellBorderColor), cellBounds); } if (paintParts == DataGridViewPaintParts.SelectionBackground || Selected) { graphics.FillRectangle(new SolidBrush(cellStyle.SelectionBackColor), cellBounds); } var col = OwningColumn as DataGridViewCheckBoxTextColumn; if (col != null && !string.IsNullOrEmpty(col.Text)) { graphics.DrawString(col.Text, cellStyle.Font, new SolidBrush(Selected ? cellStyle.SelectionForeColor : cellStyle.ForeColor), new Point(cellBounds.X + 25, cellBounds.Y + cellBounds.Height / 4)); } CheckBoxRenderer.DrawCheckBox(graphics, new Point(cellBounds.X + 4, cellBounds.Y + cellBounds.Height / 4), CheckState); base.Paint(graphics, clipBounds, cellBounds, rowIndex, cellState, value, formattedValue, errorText, cellStyle, advancedBorderStyle, paintParts); } /// <summary> /// <summary> /// 当前复选框的状态 /// </summary> private CheckBoxState CheckState { set; get; } protected override void OnMouseDown(DataGridViewCellMouseEventArgs e) { var check = (bool)Value; CheckState = check ? CheckBoxState.CheckedPressed : CheckBoxState.UncheckedPressed; base.OnMouseDown(e); } protected override void OnMouseUp(DataGridViewCellMouseEventArgs e) { var check = (bool)Value; Value = !check; SetValue(RowIndex, Value); CheckState = check ? CheckBoxState.CheckedNormal : CheckBoxState.UncheckedNormal; base.OnMouseUp(e); } public override Type ValueType { get { Type valueType = base.ValueType; if (valueType != null) { return valueType; } return defaultValueType; } } public override object DefaultNewRowValue { get { return true; } } }
最后才需要再定义这个新建的列
public class DataGridViewCheckBoxTextColumn : DataGridViewColumn { public DataGridViewCheckBoxTextColumn() : base() { CellTemplate = new DataGridViewCheckBoxTextCell(); } public override DataGridViewCell CellTemplate { get { return base.CellTemplate; } set { if (value != null && !value.GetType().IsAssignableFrom(typeof(DataGridViewCheckBoxTextCell))) { throw new Exception("这个列里面必须绑定MyDataGridViewCheckBoxCell"); } base.CellTemplate = value; } } public override object Clone() { DataGridViewCheckBoxTextColumn col = (DataGridViewCheckBoxTextColumn)base.Clone(); col.Text = Text; return col; } public string Text { set; get; } }
如果这个列是定义在控件类库内,那么引用到项目里面的时候,就能够直接在编辑器内添加这个列。如图:
最终效果图:
想找一个无人的角落发呆……