I have a DataGridView bound to a list of objects, and I'm setting a dynamic cell background colour using the CellFormatting event, as in this answer. This works well for every column except the DataGridViewCheckboxColumn. When I click inside this cell (but outside the checkbox) the cell background changes to the default white.
Visually it looks like cell selection is occurring, despite my best efforts to stop it. My cell formatting code sets the SelectionBackColor as well as the BackColor. I've disabled cell selection using the CellStateChanged event, and none of the other columns are selectable:
private void PlayerGrid_CellStateChanged(object sender, DataGridViewCellStateChangedEventArgs e)
{
if (e.StateChanged == DataGridViewElementStates.Selected)
e.Cell.Selected = false;
}
Is there an extra workaround to override the cell behaviour for checkboxes?
I've found a workaround by adding the following code to the CellStateChanged event:
if (e.Cell is DataGridViewCheckBoxCell)
e.Cell.Style.BackColor = BackgroundColor(e.Cell.RowIndex);
(BackgroundColor() calculates the cell background colour based on the row.)
This cures the problem, but could cause performance issues for larger or virtual tables, by causing creation of extra style objects.
I rather like this approach for what I'm doing. It's able to agnostically change background color (including Checkbox) of ANY of the DataGridView cells with a mouse click or Tab--for example purposes--to highlight the currently selected cell. I found other approaches oddly did not color the background of the checkbox as other cell types were colored. In my example, I'm using this approach in the CellFormatting event but I believe a similar syntax can be duplicated with success elsewhere. Also, I believe this more closely answers the OPs question as it relates to, specifically, the CellFormatting event.
void dgv_CellFormatting(object sender, DataGridViewCellFormattingEventArgs e)
{
if (W.mf.dgv.CurrentCell != null && e.RowIndex==W.mf.dgv.CurrentCell.RowIndex & e.ColumnIndex==W.mf.dgv.CurrentCell.ColumnIndex)
{
W.mf.dgv.Rows[e.RowIndex].Cells[e.ColumnIndex].Style.SelectionBackColor = Color.YellowGreen;
}
else
{
W.mf.dgv.Rows[e.RowIndex].Cells[e.ColumnIndex].Style.SelectionBackColor = W.mf.dgv.DefaultCellStyle.SelectionBackColor;
}
}
Related
I'm a beginner in C# and I'm trying to style a DataGridView button in Windows Forms.
I don't know how to, as example, remove the border from a button or change the hover color.
Many configurations that are on a normal button are missing in the DataGridView settings.
How can I achieve a full editable button inside DataGridView?
Datagridview works a little different than normal buttons,
but you can still edit several things in it if you search for the subproperties inside the properties. Let's go in a bit of detail:
DefaultCellStyle
Once you've selected your dataGridView, go to properties > RowTemplate. In there, you find something called DefaultCellStyle. if you press on the '...' at the right. then it'll open a popup that allows you to change some of the standard design of the Cells.
The same can also be applied to ColumnHeadersDefaultCellStyle, which is almost the same as DefaultCellStyle.
Columns
You can also go to Columns and add a new Column. After you've added a new column, you're also able to set several properties unique to that Column as well. You can even set all the cells in a Column to act as buttons!
Datagridview has certainely the access to customise, but most of them are divided in the cellstyles and column collections.
Changing the backcolor on hover
This in't as easily done as on a normal button, I did a search and came with this solution:
In properties, at the lightning button, you can see the events, there you can doubleclick on 'CellMouseMove' and add this. (Change the datagridview1 name eventually to be equall to yours)
private void dataGridView1_CellMouseMove(object sender, DataGridViewCellMouseEventArgs e)
{
dataGridView1.Rows[e.RowIndex].Cells[e.ColumnIndex].Style.BackColor = Color.Blue;
}
Then doubleclick the 'CellMouseLeave' event so it can revert the color.
private void dataGridView1_CellMouseLeave(object sender, DataGridViewCellEventArgs e)
{
dataGridView1.Rows[e.RowIndex].Cells[e.ColumnIndex].Style.BackColor = Color.White;
}
I hope this has helped you further.
My program outputs information froma DataTable I collect form sql data into a DataGridview and the last column in the DGV is a checkbox. I want to know if there's any quick way/event I could use so whenever a user clicks and drags to make a large selection (like in the image, clicking on the second cell and dragging down), all the selected cells change their status as if the user had clicked on each individual checkbox?
The goal is to have a quick bulk-edit way to check large selections since that's a lot easier than checking each individual checkbox.
If there's no event handler for drag-selecting, how would I get the bounds of a large selection (start cell, end cell)?
As the standard behaviour deosn't work with DGV CheckBoxesCells without a little coding here is how I would do it, staying with the normal Windows UI style, that is checking (and unchecking) CheckBoxes with the Space bar:
private void DGV_KeyDown(object sender, KeyEventArgs e)
{
if( e.KeyCode == Keys.Space && DGV.CurrentCell.ColumnIndex == yourCheckBoxColumn)
{
foreach (DataGridViewCell cell in DGV.SelectedCells)
if (cell.ColumnIndex == yourCheckBoxColumn)
cell.Value = !((bool)cell.FormattedValue);
}
}
I repeat the check to avoid crashes on cross selections..
Note that I decided to inverse each Checkmark; this way even complicated selection can be achived easily. I like that. Your mileage may vary: You may e.g. want to pick out the first Cell and set all cells to the opposite of its value.. This really depends on your users!
I populated a DataGridView with a DataTable that contains plain text. Later, I set a specific cell's background color using:
grid.Rows[row].Cells[col].Style.BackColor = setColor;
This works fine until I click on the column sort button in the DataGridView. I would like to know if there is a way to maintain the background color after sorting, irrespective of the text value of the cell. Once I set that cell's background color, it will remember that background color after sorting.
I have seen other examples using the
CellFormatting(object sender, System.Windows.Forms.DataGridViewCellFormattingEventArgs e)
Event Handler, but the code they write here always seems to have a preconceived notion of what color the cell's background needs to be in relation to the cell's text content (ex: if cellText == "Critical" ...). That will not work in my case, I just need it to remember which cells are set to a specific color.
Any help?
Use the "DataBindingComplete" event !
e.g.
private void dataGridView1_DataBindingComplete(object sender, DataGridViewBindingCompleteEventArgs e)
{
foreach (DataGridViewRow row in dataGridView1.Rows)
if (Convert.ToDateTime(row.Cells["Effective Date"].Value) > DateTime.Now)
{
row.DefaultCellStyle.BackColor = Color.LightYellow;
}
else { row.DefaultCellStyle.BackColor = Color.LightGreen; }
}
Here is what I had to do (thanks to the pointers from Sinatr) : I had to create a second DataTable that is used solely to keep track of which cells are what colors. Then, I had to add a hidden column to the DataGridView which is used as a key. I put the row number of the DataTable in this field so that after it gets sorted, I can use that row-number key to determine the row index into my Color Table. I added code in the DataGridView's CellFormatting to check the Color Table and reapply the color formatting. To make matters a little more complicated, I was having issues on getting the 1st column to become invisible, so I had to ensure that my hidden column was not the first column.
Overall I feel like these steps were hacks to get around the poorly designed and buggy DataGridView. I can't imagine a scenario where you would want to color a cell, and then have it revert colors after sorting. Sorting, in my mind, is just a rearrangement, NOT changing properties or values. I'm sure DataGridView is great and flexible for so many application, but this seems like a fundamental bug or design flaw.
I know this is a little old but the correct way to color DataGridView cells and maintain colors is to use the RowPrePaint event. That way you don't have to re-process the rows "manually" in any future changes to the DataGridView.
What I do is add additional columns or you can use a separate datatable to hold changes. Then using this event doing something similar to this:
private void dgvResults_RowPrePaint(object sender, DataGridViewRowPrePaintEventArgs e)
{
bool.TryParse(dgvResults.Rows[e.RowIndex].Cells["IsChanged"].Value.ToString(), out bool bIsChanged);
if(bisChanged)
dgvUsers.Rows[e.RowIndex].Cells["MyCellName"].Style.BackColor = Color.Salmon;
}
I'm trying to change DataGridViewCheckBoxColumn's items via this code
foreach (DataGridViewRow dgvUser in UsersGrid.Rows)
{
dgvUser.Cells["ChkSelect"].Value = true;
}
the value of checkboxs changed but the checkboxs on UI stay uncheck.
How to do it ?
You need to update the Datagridview and Refresh then.
DataGrid_ABC.Update(); in order to update the changes in the gridview
The problem here is that the DataGridViewCheckboxCell acts differently from other cells. For some reason, the property which is used to determine how the checkbox should be drawn (checked or unchecked) is not Value but FormattedValue
My feeling though is that that the Value setter has been overriden in DataGridViewCheckBoxCell to act correctly. So if you call it on a DataGridViewCell you are using the base one (which does not affect FormattedValue) while if you cast the cell things should work:
((DataGridViewCheckBoxCell) dgvUser.Cells["ChkSelect"]).Value = true;
I had this exact problem when I tried clearing other checkbox columns in the same row (performed within the CellValueChanged method). To fix my issue, I needed the following code:
private void dgv_CellContentClick(object sender, DataGridViewCellEventArgs e)
{
// filter for valid DataGridViewCheckBoxCell columns, if desired
dgv.CommitEdit(DataGridViewDataErrorContexts.Commit);
}
I am trying to set the background color of a DataGridView row to red. I tried with the following line:
dgvActiveCalls.Rows[1].DefaultCellStyle.BackColor = Color.Red;
but it doesn't work. Then just to see if something is wrong with update I tried to paint the column instead of row:
dgvActiveCalls.Columns[1].DefaultCellStyle.BackColor = Color.Red;
and it worked fine. I would be really thankful if anyone could show the way to paint the DataGridView row.
Thanks!
Make sure that the default style isn't being overriden by another of the styles. Interesting quirk of DGV in 2.0: Seems like the inheritence chain is almost upside down from what you'd expect. If you are dynamically adding columns, your DefaultCellStyle can be ignored and be overridden by the RowsDefaultCellStyle. Sorting can also override styles you've set.
You might want to check in which order you're setting these styles and google for some articles regarding style inheritence.
P.S. Interestingly enough, I googled to find a link to provide, and came across this blog with an almost identical explanation:
http://yakkowarner.blogspot.com/2008/06/datagridview-style-inheritance.html
I tested that on my machine and it worked fine. Are you sure that line isn't highlighted? If it's highlighted you'll see the highlighted color, not the red.
I suggest that you put that code inside of the DataGridView's RowPrePaint event. For example:
private void dgv_RowPrePaint(object sender, DataGridViewRowPrePaintEventArgs e)
{
/*Here you put your validation in order to paint only the row that you want*/
if (e.RowIndex == 1)
{
DataGridViewRow row = ((DataGridView)sender).Rows[e.RowIndex];
row.DefaultCellStyle.BackColor = Color.Red;
}
}