Though .Net allows to include Checkboxes in a datagridview,selection of all the checkboxes in a single column at once is always a tough task.I found it very tough initially.
Today I shall help you include a top Checkbox,clicking on which selection of all the checkboxes under that is possible.
public delegate void CheckBoxClickedHandler(bool state);
public class DataGridViewCheckBoxHeaderCellEventArgs : EventArgs
{
bool _bChecked;
public DataGridViewCheckBoxHeaderCellEventArgs(bool bChecked)
{
_bChecked = bChecked;
}
public bool Checked
{
get { return _bChecked; }
}
}
class DatagridViewCheckBoxHeaderCell : DataGridViewColumnHeaderCell
{
Point checkBoxLocation;
Size checkBoxSize;
bool _checked = false;
Point _cellLocation = new Point();
System.Windows.Forms.VisualStyles.CheckBoxState _cbState =
System.Windows.Forms.VisualStyles.CheckBoxState.UncheckedNormal;
public event CheckBoxClickedHandler OnCheckBoxClicked;
public DatagridViewCheckBoxHeaderCell()
{
}
protected override void Paint(System.Drawing.Graphics graphics,
System.Drawing.Rectangle clipBounds,
System.Drawing.Rectangle cellBounds,
int rowIndex,
DataGridViewElementStates dataGridViewElementState,
object value,
object formattedValue,
string errorText,
DataGridViewCellStyle cellStyle,
DataGridViewAdvancedBorderStyle advancedBorderStyle,
DataGridViewPaintParts paintParts)
{
base.Paint(graphics, clipBounds, cellBounds, rowIndex,
dataGridViewElementState, value,
formattedValue, errorText, cellStyle,
advancedBorderStyle, paintParts);
Point p = new Point();
Size s = CheckBoxRenderer.GetGlyphSize(graphics,
System.Windows.Forms.VisualStyles.CheckBoxState.UncheckedNormal);
p.X = cellBounds.Location.X +
(cellBounds.Width / 2) - (s.Width / 2);
p.Y = cellBounds.Location.Y +
(cellBounds.Height / 2) - (s.Height / 2);
_cellLocation = cellBounds.Location;
checkBoxLocation = p;
checkBoxSize = s;
if (_checked)
_cbState = System.Windows.Forms.VisualStyles.
CheckBoxState.CheckedNormal;
else
_cbState = System.Windows.Forms.VisualStyles.
CheckBoxState.UncheckedNormal;
CheckBoxRenderer.DrawCheckBox
(graphics, checkBoxLocation, _cbState);
}
protected override void OnMouseClick(DataGridViewCellMouseEventArgs e)
{
Point p = new Point(e.X + _cellLocation.X, e.Y + _cellLocation.Y);
if (p.X >= checkBoxLocation.X && p.X <=
checkBoxLocation.X + checkBoxSize.Width
&& p.Y >= checkBoxLocation.Y && p.Y <=
checkBoxLocation.Y + checkBoxSize.Height)
{
_checked = !_checked;
if (OnCheckBoxClicked != null)
{
OnCheckBoxClicked(_checked);
this.DataGridView.InvalidateCell(this);
}
}
base.OnMouseClick(e);
}
}
This class needs to be included to the project to get the Header Checkbox feature.
Then the checkbox need to be added to the datagridview as a DatagridViewCheckBoxColumn.
Then we assign the header to it.
The header is assigned an event with the help of which we can uncheck or check all the checkboxes.
The code to add the checkbox to header and the corresponding event code is given below.
private void FormatGrid()
{
DataView dv = new DataView();
dv.Table = _loginDs.Tables[0];
DataGridViewCheckBoxColumn chkbox = new DataGridViewCheckBoxColumn();
DatagridViewCheckBoxHeaderCell chkHeader = new DatagridViewCheckBoxHeaderCell();
chkbox.HeaderCell = chkHeader;
chkHeader.OnCheckBoxClicked += new CheckBoxClickedHandler(chkHeader_OnCheckBoxClicked);
_chkBoxGrid.Columns.Add(chkbox);
DataGridViewTextBoxColumn uname = new DataGridViewTextBoxColumn();
uname.HeaderText = "user";
uname.Name = "username";
uname.DataPropertyName = "username";
_chkBoxGrid.Columns.Add(uname);
_chkBoxGrid.DataSource = dv;
}
void chkHeader_OnCheckBoxClicked(bool state)
{
foreach (DataGridViewRow row in _chkBoxGrid.Rows)
row.Cells[0].Value = state;
}
In the checkbox header clicked event,any conditions might be added to select only the needed rows..
I hope you'll have a good time working with the new header for checkboxes. :)
32 comments:
Thanks very much for your posting. I found this one on MSDN:
http://forums.microsoft.com/MSDN/ShowPost.aspx?PostID=1197832&SiteID=1
I'll try yours first.
--kaborka
Your code worked PERFECTLY! Well done! You should post it on dodeproject.com or sourceforge.net.
Thank you very much.
--kaborka
I implemented this and it worked. Except that the first cell doesn't get selected. Do you have any idea why?
Hi Tulika,
The first checkbox is actually selected.It wont be seen as the selection will also be in the same cell.Just click on some other cell you can see that it is selected.
I had the same problem as Tulika. I added this to the OnCheckBoxClicked method:
_chkBoxGrid.BeginEdit(true);
if(_chkBoxGrid.Rows[i].Cells[_chkBoxGrid.Columns.Count - 1].Selected)
{ _chkBoxGrid.Rows[i].Cells[_chkBoxGrid.Columns.Count - 1].Selected = false;
} _chkBoxGrid.Rows[i].Cells[_chkBoxGrid.Columns.Count - 1].Value = state; _chkBoxGrid.EndEdit();
Then all went well.
Thanks for the new addition in my code...I dint find time to test it yet as I am busy with something else.But I am sure it will work well...
maybe for somebody will be usefull, some manipulations for settings width:
private void MainForm_Shown(object sender, EventArgs e)
{
//для подгонки ширины столбца с чекбоксами по содержимому выполняю следующий финт ушами:
myDataGridView.Columns["Checked"].AutoSizeMode = DataGridViewAutoSizeColumnMode.AllCellsExceptHeader;
myDataGridView.Columns["Checked"].Width = myDataGridView.Columns["Checked"].Width;
myDataGridView.Columns["Checked"].AutoSizeMode = DataGridViewAutoSizeColumnMode.None;
}
The code works perfectly, but now I cannot check each row individually. I can have all checked, or none. I want the possibility to check or uncheck each row individually too.
Thanks!
--Rodrigo
Hi Rodrigo,
Something must have gone wrong with your code. It is possible to check/uncheck individual rows with the code provided in the blog. Please post your code so that we can help you out.
Thanks,
Vimal Raj
Hi there,
thumbs up for this code! :)
i also improved the eventargs so it can be used more like the other datagrid events:
public delegate void CheckBoxClickedHandler(object sender, DataGridViewCheckBoxHeaderCellEventArgs e);
public class DataGridViewCheckBoxHeaderCellEventArgs : EventArgs
{
public DataGridViewCheckBoxHeaderCellEventArgs(bool bChecked, int index)
{
Checked = bChecked;
ColumnIndex = index;
}
public bool Checked { get; private set; }
public int ColumnIndex { get; private set; }
}
Hi KeksImperium,
Thanks for sharing your code.
Happy Programming,
Vimal Raj
how do you include the class to your project if you already have a code ehind file? I made a c sharp file in my app code directory and put it in there, but is there like a using line or add namespace thing I ahve to do?
any help would be greatly appreciated!
thanks
Hi Dan,
You can add the class file to AppCode folder and it will be readily available in your other pages. You don't have to add any reference or using statements.
In Visual Studio, you can right click AppCode Folder and select 'Add New Item' and then 'Class'.
The newly created class will be available in other code files. (You can find it listed in intellisense drop down).
Hope this helps,
Happy Programming,
Vimal Raj
Hi Salu,
Thanks for your code. It's very useful.
Ann.
My Pleasure... Ann...
This does not work in case we assign a data property to the column. If I have to assign DataPropertyName then how can achieve the same functionality?
Hi Jayant,
This code should very well work with DataPropertyName. If you are getting any specific errors, Please let me know.
Thanks,
Vimal Raj
Thanks for the code.
I translated this into VB which i am writting in and got an error with the class, here goes:
Protected Overloads Overrides Sub OnMouseClick(ByVal e As DataGridViewCellMouseEventArgs)
Dim p As New Point(e.X + _cellLocation.X, e.Y + _cellLocation.Y)
If p.X >= checkBoxLocation.X AndAlso p.X <= checkBoxLocation.X + checkBoxSize.Width AndAlso p.Y >= checkBoxLocation.Y AndAlso p.Y <= checkBoxLocation.Y + checkBoxSize.Height Then
_checked = Not _checked
If OnCheckBoxClicked IsNot Nothing Then
RaiseEvent OnCheckBoxClicked(_checked)
Me.DataGridView.InvalidateCell(Me)
End If
End If
MyBase.OnMouseClick(e)
End Sub
The "If OnCheckBoxClicked IsNot Nothing Then" line says it is an event and can not be called directly. You may notice I changed the line below it to "RaiseEvent..." in order to get rid of the error on that line. However, the same will not do for the condition testing line. Any ideas how I resolve this error?
Thanks
I too have converted it to VB code, but i am not getting a checkbox at the columnheader that allows the user to select all.
This is simple Code
public partial class Form1 : Form
{
public Form1()
{
InitializeComponent();
}
private void Form1_Load(object sender, EventArgs e)
{
c1 = new DataGridViewCheckBoxColumn();
c1.Name = "selection";
c1.HeaderCell.Style.Alignment = DataGridViewContentAlignment.MiddleCenter;
this.dataGridView1.Columns.Add(c1);
this.dataGridView1.Rows.Add();
this.dataGridView1.Rows.Add();
this.dataGridView1.Rows.Add();
this.dataGridView1.Rows.Add();
ckBox = new CheckBox();
//Get the column header cell bounds
Rectangle rect =
this.dataGridView1.GetCellDisplayRectangle(0, -1, true);
ckBox.Size = new Size(18, 18);
//Change the location of the CheckBox to make it stay on the header
ckBox.Location = rect.Location;
ckBox.CheckedChanged += new EventHandler(ckBox_CheckedChanged);
//Add the CheckBox into the DataGridView
this.dataGridView1.Controls.Add(ckBox);
}
DataGridViewCheckBoxColumn c1;
CheckBox ckBox;
void ckBox_CheckedChanged(object sender, EventArgs e)
{
for (int j = 0; j < this.dataGridView1.RowCount; j++)
{
this.dataGridView1[0, j].Value = this.ckBox.Checked;
}
this.dataGridView1.EndEdit();
}
}
Lots of Thanks ,
for sharing your knowledge
It will be useful for many in need.
Hi Anna,
Its my pleasure to share my knowledge with the community...
keep visiting Techisolutions.info
For just selection, this works just fine:
for (int i=0;i < dgItems.Rows.Count;i++)
{
if (this.dgItems.Rows[i].Cells[0].Value == null)
this.dgItems.Rows[i].Cells[0].Value = true;
}
Ouch.. That's a lot of code just for that!
Why dont you just use the following:
VB.net code
For i = 0 To datagridview1.Rows.Count - 1
datagridview1.Item(0, i).Value = True
Next
Hi there!
I think it would be a good idea to show a Header-text beside the checkbox.
Add this to the Class.
//member for Headertext
string _headerText = string.Empty;
//Constructor
public DatagridViewCheckBoxHeaderCell(string headerText) {_headerText = headerText;}
// with Headertext locate the checkbox on the left
if (_headerText == string.Empty)
{
p.X = cellBounds.Location.X + (cellBounds.Width / 2) - (s.Width / 2);}
else
{
p.X = cellBounds.Location.X + 1;
}
// Paint the HeaderText
if(_headerText != string.Empty)
CheckBoxRenderer.DrawCheckBox(graphics, checkBoxLocation, new Rectangle(p.X + s.Width + 2, p.Y, cellBounds.Width - s.Width - 4, s.Height), _headerText, cellStyle.Font, false, _cbState);
else
CheckBoxRenderer.DrawCheckBox(graphics, checkBoxLocation, _cbState);
Have fun!
Hi Hoerg,
Thanks for your code.
Happy Programming,
Vimal Raj
Some generic (almost) code for
the event handler:
void ckBox_CheckedChanged(object sender, EventArgs e)
{
CheckBox cb = sender as CheckBox;
DataGridView dgv = (DataGridView)cb.Parent;
foreach (DataGridViewRow row in dgv.Rows)
{
row.Cells[0].Value = cb.Checked;
}
}
The only assumption is that the CheckBox column is the first one which it normally is.
Thanks, just what I needed.
I want to create a data grid view with check boxes in column headers. how can i create the data grid view using c#.Net 3.5?
@all
use this.. this is perfect
http://social.msdn.microsoft.com/forums/en-US/winformsdatacontrols/thread/827907ea-c529-4254-9b15-2e6d571f5c5b/
Setting 'DataPropertyName' stopped the OnCheckBoxClicked event firing.
Hi
I found the cause of this problem & the solution.
When 'DataPropertyName' is set it looks like the custom headerCell is cloned a number of times (possibly on painting the container).
The custom class dose not override the clone method so any handlers registered for the event are not copied to the newly cloned headerCell.
Adding the following solves the problem:
public override object Clone()
{
DatagridViewCheckBoxHeaderCell obj = (DatagridViewCheckBoxHeaderCell)base.Clone();
obj._checkBoxLocation = _checkBoxLocation;
obj._checkBoxSize = _checkBoxSize;
obj._checked = _checked;
obj._cellLocation = _cellLocation;
obj._cbState = _cbState;
obj.OnCheckBoxClicked = OnCheckBoxClicked;
return obj;
}
Hope this helps
Trevor
Hello Everyone,
this is great article!!!! thanks for sharing with us!!!! quite entertained, you may check out the following links for simplest one and more details.....
http://mindstick.com/Articles/77b73daa-2307-4de6-91df-7d6fe1094731/?Checkbox%20in%20DataGridView
Thanks !!!
Post a Comment