做个项目需要用到DataGridView,这个控件还是挺好用的,但是今天却发现无法实现自己想要的功能。主要是DataGridViewCheckBoxColumn这个列虽然是提供了复选框,但是却未能在复选框的旁边提供文本的显示。在网上搜索了一下,提供的方法很多都是弄两列,然后合并单元格,将两列合并成为了一列。不过我不太喜欢那种方式,于是就自己重写了一下DataGridViewColumn,略显简陋,只实现了最基本的功能,现在拿出来,希望各位能够提一些好的意见和见解。
public class DataGridViewCheckBoxLabelColumn : DataGridViewColumn { public DataGridViewCheckBoxLabelColumn() : base() { CellTemplate = new DataGridViewCheckBoxCell(); } /// <summary> /// 获取和设置用于创建新单元格的模板 /// </summary> public override DataGridViewCell CellTemplate { get { return base.CellTemplate; } set { if (value != null && !value.GetType().IsAssignableFrom(typeof(DataGridViewCheckBoxCell))) { throw new Exception("这个列里面必须绑定DataGridViewCheckBoxCell"); } base.CellTemplate = value; } } protected override void OnDataGridViewChanged() { var dgv = this.DataGridView; int count = dgv.Rows.Count; for (int i = 0; i < count; i++) { if (dgv.Rows[i].Cells[Name] is DataGridViewCheckBoxCell) { var cell = dgv.Rows[i].Cells[Name] as DataGridViewCheckBoxCell; cell.Text = Text; } } base.OnDataGridViewChanged(); } /// <summary> /// 复选框的文本 /// </summary> public string Text { set; get; } public override object Clone() { DataGridViewCheckBoxLabelColumn col = (DataGridViewCheckBoxLabelColumn)base.Clone(); col.Text = Text; return col; } } public class DataGridViewCheckBoxCell : DataGridViewCell { public DataGridViewCheckBoxCell() : base() { } /// <summary> /// 要显示的文本 /// </summary> public string Text { set; get; } public override object Clone() { DataGridViewCheckBoxCell cell = (DataGridViewCheckBoxCell)base.Clone(); cell.Text = Text; return cell; } /// <summary> /// 单元格的背景色 /// </summary> private Color CellBackColor { get { return Selected ? Color.FromArgb(49, 106, 197) : OwningRow.DataGridView.BackgroundColor; } } /// <summary> /// 单元格前景色 /// </summary> private Color CellForeColor { get { return Selected ? Color.White : OwningRow.DataGridView.ForeColor; } } /// <summary> /// 单元格边框颜色 /// </summary> private Color CellBorderColor { get { return Color.FromArgb(172, 168, 153); } } /// <summary> /// 钩子的颜色 /// </summary> private Color HookColor { get { return Color.FromArgb(33, 161, 33); } } /// <summary> /// 复选框边框颜色 /// </summary> private Color CheckBoxBorderColor { get { return Color.FromArgb(28, 81, 128); } } public delegate void CheckedChangedHandle(object sender, DataGridViewCheckBoxLabelCheckedChangedEventArgs e); /// <summary> /// 单选框的选中状态发生变化时 /// </summary> public event CheckedChangedHandle CheckedChanged; protected override void Paint(System.Drawing.Graphics graphics, System.Drawing.Rectangle clipBounds, System.Drawing.Rectangle cellBounds, int rowIndex, DataGridViewElementStates elementState, object value, object formattedValue, string errorText, DataGridViewCellStyle cellStyle, DataGridViewAdvancedBorderStyle advancedBorderStyle, DataGridViewPaintParts paintParts) { var cell = new Rectangle(cellBounds.X, cellBounds.Y, cellBounds.Width - 1, cellBounds.Height - 1); graphics.FillRectangle(new SolidBrush(CellBackColor), cell); graphics.DrawLine(new Pen(CellBorderColor), new Point(cell.X + cell.Width, cell.Y), new Point(cell.X + cell.Width, cell.Y + cell.Height)); graphics.DrawLine(new Pen(CellBorderColor), new Point(cell.X, cell.Y + cell.Height), new Point(cell.X + cell.Width, cell.Y + cell.Height)); var check = formattedValue.Equals("True") || formattedValue.Equals("true"); var box = new Rectangle(cellBounds.X + 4, cellBounds.Y + (cellBounds.Height - 12) / 2, 12, 12); graphics.FillRectangle(new SolidBrush(Color.White), box); graphics.DrawRectangle(new Pen(CheckBoxBorderColor, 1.5f), box); if (check) { graphics.DrawString("√", new Font("宋体", 8.0f, FontStyle.Bold), new SolidBrush(HookColor), new PointF(box.X - 2, box.Y + 2)); } if (!string.IsNullOrEmpty(Text)) { var s = graphics.MeasureString(Text, OwningRow.DataGridView.Font); var x = box.X + box.Width + 2; var y = cellBounds.Y + (cellBounds.Height - s.Height) / 2 + 1; graphics.DrawString(Text, OwningRow.DataGridView.Font, new SolidBrush(CellForeColor), new PointF(x, y)); } base.Paint(graphics, clipBounds, cellBounds, rowIndex, elementState, value, formattedValue, errorText, cellStyle, advancedBorderStyle, paintParts); } protected override bool MouseClickUnsharesRow(DataGridViewCellMouseEventArgs e) { if (e.Button == MouseButtons.Left) { var p = new Point(e.X, e.Y); var row = this.OwningRow; var x = 4; var y = (row.Height - 12) / 2; var r = new Rectangle(x, y, 12, 12); if (r.Contains(p)) { var check = FormattedValue.Equals("True") || FormattedValue.Equals("true"); Value = !check; this.SetValue(RowIndex, Value); if (CheckedChanged != null) CheckedChanged(this, new DataGridViewCheckBoxLabelCheckedChangedEventArgs(!check, RowIndex, ColumnIndex)); RaiseCellValueChanged(new DataGridViewCellEventArgs(ColumnIndex, RowIndex)); } } return base.MouseClickUnsharesRow(e); } } public class DataGridViewCheckBoxLabelCheckedChangedEventArgs : EventArgs { public DataGridViewCheckBoxLabelCheckedChangedEventArgs() : base() { } /// <summary> /// /// </summary> /// <param name="check">当前单选框是否被选中</param> /// <param name="rowIndex">单元格所在行的行号</param> /// <param name="columnIndex">单元格所在列的列号</param> public DataGridViewCheckBoxLabelCheckedChangedEventArgs(bool check, int rowIndex, int columnIndex) : base() { Checked = check; RowIndex = rowIndex; ColumnIndex = columnIndex; } /// <summary> /// 当前单选框是否被选中 /// </summary> public bool Checked { set; get; } /// <summary> /// 单元格所在行的行号 /// </summary> public int RowIndex { set; get; } /// <summary> /// 单元格所在列的列号 /// </summary> public int ColumnIndex { set; get; } }
在使用了重写的列后,就基本实现了复选框的选中变化,并呈现了复选框旁边的文本,效果图如下: