C#WinForm下DataGridView单选按钮列和⽀持三种选择状态的复选框列的实现在C# WinForm下做过项⽬的朋友都知道,其中的DataGridView控件默认只⽀持DataGridViewButtonColumn、DataGridViewCheckBoxColumn、DataGridViewComboBoxColumn、DataGridViewImageColumn、DataGridViewLinkColumn和DataGridViewTextBoxColumn六种列类型,如果你想要在DataGridView的列中添加其它的⼦控件,则需要⾃⼰实现DataGridViewColumn和DataGridViewCell,这就意味着你需要从现有的列中继承并改写⼀些⽅法,如实现⼀个⽀持单选按钮的列,或⽀持三种选择状态的多选按钮的列。
上⾯两个截图分别为RadioButton列和⽀持三种状态的CheckBox列在DataGridView中的实现效果,我是在Windows 2003中实现的,因此显⽰的效果跟在XP和Vista下有些区别,Vista下CheckBox的第三种状态(不确定状态)显⽰出来的效果是⼀个实⼼的蓝⾊⽅块。
下⾯我看具体来看看如何实现这两种效果。
要实现⾃定义的DataGridView列,你需要继承并改写两个类,⼀个是基于DataGridViewColumn的,⼀个是基于DataGridViewCell的,因为RadionButton和CheckBox的实现原理类似,因此我们可以将这两种列采⽤同⼀种⽅法实现。创建DataGridViewDisableCheckBoxCell和DataGridViewDisableCheckBoxColumn两个类,分别继承⾃DataGridViewCheckBoxCell和DataGridViewCheckBoxColumn。代码如下:
public class DataGridViewDisableCheckBoxCell: DataGridViewCheckBoxCell
{
public bool Enabled { get; set; }
// Override the Clone method so that the Enabled property is copied.
public override object Clone()
{
DataGridViewDisableCheckBoxCell cell = (DataGridViewDisableCheckBoxCell)base.Clone();
cell.Enabled = this.Enabled;
return cell;
}
// By default, enable the CheckBox cell.
public DataGridViewDisableCheckBoxCell()
{
this.Enabled = true;
}
// Three state checkbox column cell
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)
{
// The checkBox cell is disabled, so paint the border, background, and disabled checkBox for the cell.
if (!this.Enabled)
{
// Draw the cell background, if specified.
if ((paintParts & DataGridViewPaintParts.Background) == DataGridViewPaintParts.Background)
{
SolidBrush cellBackground = new SolidBrush(cellStyle.BackColor);
graphics.FillRectangle(cellBackground, cellBounds);
cellBackground.Dispose();
}
// Draw the cell borders, if specified.
if ((paintParts & DataGridViewPaintParts.Border) == DataGridViewPaintParts.Border)
{
PaintBorder(graphics, clipBounds, cellBounds, cellStyle, advancedBorderStyle);
}
// Calculate the area in which to draw the checkBox.
CheckBoxState state = CheckBoxState.MixedDisabled;
Size size = CheckBoxRenderer.GetGlyphSize(graphics, state);
Point center = new Point(cellBounds.X, cellBounds.Y);
center.X += (cellBounds.Width - size.Width) / 2;
checkbox和radiobutton的区别center.Y += (cellBounds.Height - size.Height) / 2;
// Draw the disabled checkBox.
CheckBoxRenderer.DrawCheckBox(graphics, center, state);
}
else
{
// The checkBox cell is enabled, so let the base class, handle the painting.
base.Paint(graphics, clipBounds, cellBounds, rowIndex, elementState, value, formattedValue, errorText, cellStyle, advancedBorderStyle, paintParts);
}
}
}
public class DataGridViewDisableCheckBoxColumn : DataGridViewCheckBoxColumn
{
public DataGridViewDisableCheckBoxColumn()
{
this.CellTemplate = new DataGridViewDisableCheckBoxCell();
}
}
主要是要实现DataGridViewDisableCheckBoxCell的呈现⽅式,其中设置了CheckBoxState的状态为MixedDisabled,表⽰⽀持三种状态,这个是实现效果的核⼼,如果要实现RadioButton列的效果,只需要将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)
{
// Draw the cell background, if specified.
if ((paintParts & DataGridViewPaintParts.Background) == DataGridViewPaintParts.Background)
{
SolidBrush cellBackground = new SolidBrush(cellStyle.BackColor);
graphics.FillRectangle(cellBackground, cellBounds);
cellBackground.Dispose();
}
// Draw the cell borders, if specified.
if ((paintParts & DataGridViewPaintParts.Border) == DataGridViewPaintParts.Border)
{
PaintBorder(graphics, clipBounds, cellBounds, cellStyle, advancedBorderStyle);
}
/
/ Calculate the area in which to draw the checkBox.
RadioButtonState state = value != null && (SelectedStatus)value == SelectedStatus.Selected ? RadioButtonState.CheckedNormal : RadioButtonState.UncheckedNormal;        Size size = RadioButtonRenderer.GetGlyphSize(graphics, state);
Point center = new Point(cellBounds.X, cellBounds.Y);
center.X += (cellBounds.Width - size.Width) / 2;
center.Y += (cellBounds.Height - size.Height) / 2;
// Draw the disabled checkBox.
RadioButtonRenderer.DrawRadioButton(graphics, center, state);
}
使⽤RadioButtonState代替CheckBoxState。
当然,上⾯的代码只是实现了列和单元格的显⽰效果,在使⽤过程中当⽤户点击单选或多选按钮时如何
改变状态则需要⾃⼰⼿动编写代码来实现,如在点击单选按钮时将DataGridView中其它⾏的单选按钮设置为未选择状态,点击多选按钮时在三种状态之间转换等。
⾸先我们需要⼿动修改Form的Designer.cs⽂件中的代码,将CheckBox所在的列的类型由DataGridViewCheckBoxColumn改成DataGridViewDisableCheckBoxColumn,并设置ThreeState的值为true,这个代码是需要⼿动去修改的,因为默认情况下VS不⽀持对⾃定义DataGridView列类型进⾏可视化编辑。要⽀持CheckBox的三种状态,我们还需要定义⼀个枚举来给CheckBox的TrueValue、FalseValue和IndeterminateValue赋值。这个枚举很简单,有三个成员就够了。
public enum SelectedStatus
{
Selected,
NoSelected,
Indeterminate
}
然后设置CheckBox的TrueValue=SelectedStatus.Selected,FalseValue=SelectedStatus.NoSelected,IndeterminateValue=SelectedStatus.Indeterminate。
好了!这个时候运⾏程序,可以看到经过我们改造的列已经可以正常显⽰了,但是有⼀个问题,那就是当我们点击其中的单选或多选按钮时它的状态并不能发⽣变化,这是因为我们没有在click事件中改变按钮的选择状态。要实现这个功能,你需要给宿主DataGridView定义CellContentClick事件,并且判断当⽤户点击的是否为你所指定的控件,然后进⾏相应的处理。代码如下:
private void dataGridView1_CellContentClick(object sender, DataGridViewCellEventArgs e)
{
if (e.RowIndex >= 0)
{
DataGridViewColumn column = dataGridView1.Columns[e.ColumnIndex];
if (column is DataGridViewCheckBoxColumn)
{
DataGridViewDisableCheckBoxCell cell = dataGridView1.Rows[e.RowIndex].Cells[e.ColumnIndex] as DataGridViewDisableCheckBoxCell;
if (!cell.Enabled)
{
return;
}
if ((SelectedStatus)cell.Value == SelectedStatus.NoSelected)
{
cell.Value = SelectedStatus.Selected;
}
else if ((SelectedStatus)cell.Value == SelectedStatus.Selected)
{
cell.Value = SelectedStatus.Indeterminate;
}
else
{
cell.Value = SelectedStatus.NoSelected;
}
}
}
}
这个是CheckBox的,如果是RadioButton的话你还需要控制其它RadionButton的状态,这个时候就没有三种状态⽽是两种状态了,代码可以修改成这样:
private void dataGridView1_CellContentClick(object sender, DataGridViewCellEventArgs e)
{
if (e.RowIndex >= 0)
{
DataGridViewColumn column = dataGridView1.Columns[e.ColumnIndex];
if (column is DataGridViewCheckBoxColumn)
{
DataGridViewDisableCheckBoxCell cell = dataGridView1.Rows[e.RowIndex].Cells[e.ColumnIndex] as DataGridViewDisableCheckBoxCell;
if (!cell.Enabled)
{
return;
}
if ((SelectedStatus)cell.Value == SelectedStatus.NoSelected)
{
cell.Value = SelectedStatus.Selected;
SetRadioButtonValue(cell);
}
else
{
cell.Value = SelectedStatus.NoSelected;
}
}
}
}
private void SetRadioButtonValue(DataGridViewDisableCheckBoxCell cell)
{
SelectedStatus status = (SelectedStatus)cell.Value;
if (status == SelectedStatus.Selected)
{
status = SelectedStatus.NoSelected;
}
else
{
status = SelectedStatus.Selected;
}
for (int i = 0; i < dataGridView1.Rows.Count; i++)
{
DataGridViewDisableCheckBoxCell cel = dataGridView1.Rows[i].Cells["checkbox"] as DataGridViewDisableCheckBoxCell;
if (!cel.Equals(cell))
{
cel.Value = status;
}
}
}
函数SetRadionButtonValue负责修改宿主DataGridView当前列中其它的RadionButton的状态。
在完成这些⼯作后,⼀个相对完整的⽀持RadionButton或三种状态的CheckBox列的DataGridView界⾯就完成了,你可以根据需要在接下来的代码中来判断DataGridView中哪些⾏被选中了,或者哪些⾏处于未确定的选择状态(CheckBox的第三种状态),进⽽做出判断来完成后⾯的⼯作。
最后我会提供整个⼯程供⼤家下载,其中也给出了DataGridViewLinkColumn列中的⼀些效果,如当⿏标指向超链接时显⽰⼀个ToolTip,当⽤户点击超链接时打开⼀个⽹页等。

版权声明:本站内容均来自互联网,仅供演示用,请勿用于商业和其他非法用途。如果侵犯了您的权益请与我们联系QQ:729038198,我们将在24小时内删除。