Checked List Box Item Check Event Strange Behavior [duplicate] - c#

This question already has answers here:
Which CheckedListBox event triggers after a item is checked?
(18 answers)
Closed 8 years ago.
private void checkedListBox1_ItemCheck(object sender, ItemCheckEventArgs e)
{
if (checkedListBox1.GetItemChecked(i) == false)
{
...
}
else
{
...
}
}
For some reason when the code above executes, it does the opposite of what I'd like it to do. When an item is checked for the first time it doesn't do anything, however, when it is unchecked it does what's in the else statement (again, opposite of what it's supposed to do). Is there some property that I'm forgetting about here?

You should use e.NewValue instead of checkedListBox1.GetItemChecked(i). The reason being that checkedListBox1.GetItemChecked is a cached state, because the ItemCheck event occurs before the internal value is updated.
This'll work as you are expecting:
private void checkedListBox1_ItemCheck(object sender, ItemCheckEventArgs e)
{
if (e.NewValue == CheckState.Checked)
{
...
}
else
{
...
}
}
Secondly, as to why the first time you click the checkbox, it doesn't react: that's because the CheckedListBox object requires the item to be highlighted before changing the checkbox value through mouse clicks.
In order to achieve a similar effect, set checkedListBox1.CheckOnClick = true. This will cause the checkbox to become checked whenever clicking on the checkbox or on the list item itself.

MSDN indicates that the check state isn't updated in the ItemCheck event until after it finishes. You're probably looking for e.NewValue.

Related

How to access the Index of a changed Selection in a Datagridview

I am working on a windows form. Currently I am geting quite a headache over a seemingly simple prolbem.
I have a datagridview and want to allow right click selection. Therefore I created a function called dataGridViewJobs_MouseDown that is raised on MouseDown on the datagridview:
private void dataGridViewJobs_MouseDown(object sender, MouseEventArgs e)
{
int curRowIdx = dataGridViewJobs.HitTest(e.Location.X, e.Location.Y).RowIndex;
if (curRowIdx != -1 && curRowIdx < dataGridViewJobs.Rows.Count)
{
dataGridViewJobs.CurrentCell = dataGridViewJobs[0, curRowIdx];
}
}
A hitTest is executed to find the row-index of the clicked cell. Afterwards the currentCell of the datagridview is set to the first cell in said row.
This causes the SelectionChanged-event to be raised. This is connected to the following function:
private void dataGridViewJobs_SelectionChanged(object sender, EventArgs e)
{
if (dataGridViewJobs.Rows.Count > 0)
{
Console.WriteLine(dataGridViewJobs.CurrentCell.RowIndex);
}
}
This writes the old index to the console. Why is that?
I am currently working with a workaround, which means I save the result of the hitTest in a global variable. But that can not be the right way to do this.
Am I doing something wrong? Thanks in advance!
From MSDN
When you change the value of the CurrentCell property, the
SelectionChanged event occurs before the CurrentCellChanged event. Any
SelectionChanged event handler accessing the CurrentCell property at
this time will get its previous value.
Use CurrentCellChanged event for printing current value

Datagridview Datagridcheckbox cell values not matching GUI

I have a unbound DataGridView with 6 columns, the first being a DataGridCheckBoxColumn. When a user clicks on a checkbox cell, I want to determine what cells have been checked and what ones are not. Here is my code:
private void UpdateSelectedPlaces()
{
//Clear out the places list each time the user selects a new item (or items)
_selectedPlaces.Clear();
foreach (DataGridViewRow row in placesGridView.Rows)
{
if (row.Cells[0].Value != null && row.Cells[0].Value.Equals(true))
{
_selectedPlaces.Add((TripPlace)row.DataBoundItem);
}
}
}
//Click event handler
private void placesGridView_CellContentClick(object sender, DataGridViewCellEventArgs e)
{
UpdateSelectedPlaces();
}
I am finding that the DataGridCheckBoxCells are not holding the correct value at the time of the click. This occurs for all rows. There seems to be no pattern really. I was hoping that the event was just not called at the right time (I.e. the checking of the checkbox was yet to be completed) but I cannot prove that.
In short, even though the GUI displays a checked checkbox, the back end thinks the checkbox is not checked when using .Value Is there a simpler way to just determine if each cell[0] is checked or not checked in a datagridview?
I am finding that the DataGridCheckBoxCells are not holding the
correct value at the time of the click.
This is normal and by design because you are using DataGridView.CellContentClick event. From MSDN:
Use this event to detect button clicks for a DataGridViewButtonCell or
link clicks for a DataGridViewLinkCell. For clicks in a
DataGridViewCheckBoxCell, this event occurs before the check box
changes value, so if you do not want to calculate the expected value
based on the current value, you will typically handle the
DataGridView.CellValueChanged event instead. Because that event occurs
only when the user-specified value is committed, which typically
occurs when focus leaves the cell, you must also handle the
DataGridView.CurrentCellDirtyStateChanged event.
The corrected code is similar to the other answer but unfortunately, the reason of the problem was not explained in that answer.
private void UpdateSelectedPlaces()
{
//Clear out the places list each time the user selects a new item (or items)
_selectedPlaces.Clear();
foreach (DataGridViewRow row in placesGridView.Rows)
{
if (row.Cells[0].Value != null && row.Cells[0].Value.Equals(true))
{
_selectedPlaces.Add((TripPlace)row.DataBoundItem);
}
}
}
private void placesGridView_CellValueChanged(object sender, DataGridViewCellEventArgs e)
{
UpdateSelectedPlaces();
}
private void placesGridView_CurrentCellDirtyStateChanged(object sender, EventArgs e)
{
if (placesGridView.IsCurrentCellDirty)
{
placesGridView.CommitEdit(DataGridViewDataErrorContexts.Commit);
}
}
private void placesGridView_CellValueChanged(object sender, DataGridViewCellEventArgs e)
{
Boolean bl;
if (placesGridView.Columns[e.ColumnIndex].Name == "name of check column")
{
DataGridViewCheckBoxCell checkCell = (DataGridViewCheckBoxCell)placesGridView.Rows[e.RowIndex].Cells[2]; //2 number of check column
//bl is the check box current condition.
//Change only this in your list eg list[e.RowIndex] = bl; No need to check all rows.
bl = (Boolean)checkCell.Value;
}
}
private void placesGridView_CurrentCellDirtyStateChanged(object sender, EventArgs e)
{
if (placesGridView.IsCurrentCellDirty)
{
placesGridView.CommitEdit(DataGridViewDataErrorContexts.Commit);
}
}

Radio button checked changed event fires twice

Please read my question its not a duplicate one.
I've three radio buttons on windows form and all these buttons have common 'CheckedChanged' event associated. When I click any of these radio buttons, it triggers the 'CheckedChanged' event twice.
Here is my code:
private void radioButtons_CheckedChanged(object sender, EventArgs e)
{
//My Code
}
I inserted the breakpoint and the whole code within this event iterates twice.
Please tell me why it is behaving like this?
As the other answerers rightly say, the event is fired twice because whenever one RadioButton within a group is checked another will be unchecked - therefore the checked changed event will fire twice.
To only do any work within this event for the RadioButton which has just been selected you can look at the sender object, doing something like this:
void radioButtons_CheckedChanged(object sender, EventArgs e)
{
RadioButton rb = sender as RadioButton;
if (rb != null)
{
if (rb.Checked)
{
// Only one radio button will be checked
Console.WriteLine("Changed: " + rb.Name);
}
}
}
To avoid it, just check if radioButton is checked
for example:
private void radioButton1_CheckedChanged(object sender, EventArgs e)
{
if (radioButton1.Checked)
//your code
}
CheckedChanged is raised whenever the Checked property changes. If you select a RadioButton then the previously selected RadioButton is unchecked (fired CheckedChanged), and then the new RadioButton is checked (fired CheckedChanged).
It's triggering once for the radio button transition from checked to unchecked, and again for the radio button transitioning from unchecked to checked (i.e. any change in checked state triggers the event)
You could set the AutoCheck property true for each RadioButton then catch the Click event instead of the CheckChanged event. This would ensure that only one event is fired, and the logic in the handler can cast the sender to type RadioButton if needed to process the click. Often the cast can be avoided if the handler logic is simple. Here is an example which handles three controls, rbTextNumeric, rbTextFixed and rbTextFromFile:
private void rbText_Click(object sender, EventArgs e)
{
flowLayoutPanelTextNumeric.Enabled = rbTextNumeric.Checked;
txtBoxTextFixed.Enabled = rbTextFixed.Checked;
flowLayoutPanelTextFromFile.Enabled = rbTextFromFile.Checked;
}
{
public partial class Form3 : Form
{
public Form3()
{
InitializeComponent();
}
int click = 0;
private void radioButton1_Click(object sender, EventArgs e)
{
click++;
if (click %2==1)
{
radioButton1.Checked = true;
}
if (click %2==0)
{
radioButton1.Checked = false;
}
if (radioButton1.Checked==true)
{
label1.Text = "Cheked";
}
if (radioButton1.Checked==false)
{
label1.Text = "Uncheked";
}
}
}
}
The other answers are correct but miss the reason for the underlying problem.
When a radio button is checked the first event sent is the change from the unchecked item
however if you check its state by its control name you will still see its old checked status because the form has not been updated yet. To see its true status you need to cast the sender object.
This allows you to perform any actions relating to the condition which is being deselected should you need to do so.
In the not uncommon scenario below multiple radio buttons are sent to the same handler event.
Simply checking the state of the sender for checked will not work here as we need to perform different actions depending on which radio button has been pressed.
So first we ignore any sender that has just been unchecked.
then we identify the checked sender by control name to process the correct action.
private void ModeChangedExample(object sender, EventArgs e)
{
// multiple radio buttons come here
// We only want to process the checked item.
// if you need to something based on the item which was just unchecked don't use this technique.
// The state of the sender has not been updated yet in the form.
// so checking against rdo_A check state will still show it as checked even if it has just been unchecked
// only the sender variable is up to date at this point.
// To prevent processing the item which has just been uncheked
RadioButton RD = sender as RadioButton;
if (RD.Checked == false) return;
if (rdo_A.Name == RD.Name)
{
//Do stuff
}
if (rdo_B..Name == RD.Name)
{
// Do other stuff
}
if (rdo_C.Name == RD.Name)
{
// Do something else
}
}
This problem of double checking happens when there is a series of RadioButton Clicks in succession.I had this same problem.The last click will give two results.To overcome this i made a dummy click in the end.The double click stopped.Try this method.
Venkatraman

Weird problem with DataGridViewComboBoxCell, trying to autocommit changes

So my goal is once a user clicks on the item from the dropdown list, the cell will automatically call EndEdit(). The weirdest thing is that the code below will work on the 2nd-n ComboBoxesCells that I drop down and select values from but NEVER the first one. Is there something I'm missing here??
protected override void OnCellClick(DataGridViewCellEventArgs e)
{
base.OnCellClick(e);
DataGridViewComboBoxEditingControl control = this.EditingControl as DataGridViewComboBoxEditingControl;
if (control != null)
{
control.DropDownClosed += new EventHandler(control_DropDownClosed);
}
}
void control_DropDownClosed(object sender, EventArgs e)
{
this.EndEdit();
DataGridViewComboBoxEditingControl control = sender as DataGridViewComboBoxEditingControl;
control.DropDownClosed -= new EventHandler(control_DropDownClosed);
}
Should add here that I am inheriting from DataGridView if that's not obvious
When something like "The weirdest thing is that the code below will work on the 2nd-n ComboBoxesCells that I drop down and select values from but NEVER the first one" happens, it's often because the Event happens before something you need is done.
Seing your example, I would say that the first time, when you click,
DataGridViewComboBoxEditingControl control = this.EditingControl as DataGridViewComboBoxEditingControl;
gives you control == null.
Maybe you should change the Event chosen to do your stuff from Click to SelectedIndexChanged or SelectedValueChanged ?
Hope this helps,

Triggering a checkbox value changed event in DataGridView

I have a grid view that has a check box column, and I want to trigger a drawing event as soon as the value of the cell is toggled. I tried the ValueChaged and the CellEndEdit and BeginEdit, and chose the selection mode as CellSelect. As for the the first 2 events, the event was triggered upon the finishing of the edit mode, like moving out of the current cell, or going back and forth. It's just a weird behavior.
Is there anything that triggers the event on the grid view as soon as the cell value is changed?
I use the CellContentClick event, which makes sure the user clicked the checkbox. It DOES fire multiple times even if the user stays in the same cell. The one issue is that the Value does not get updated, and always returns "false" for unchecked. The trick is to use the .EditedFormattedValue property of the cell instead of the Value property. The EditedFormattedValue will track with the check mark and is what one wishes the Value had in it when the CellContentClick is fired.
No need for a timer, no need for any fancy stuff, just use CellContentClick event and inspect the EditedFormattedValue to tell what state the checkbox is going into / just went into. If EditedFormattedValue = true, the checkbox is getting checked.
A colleague of mine recommends trapping the CurrentCellDirtyStateChanged event. See http://msdn.microsoft.com/en-us/library/system.windows.forms.datagridview.currentcelldirtystatechanged.aspx.
Another way is to handle the CellContentClick event (which doesn't give you the current value in the cell's Value property), call grid.CommitEdit(DataGridViewDataErrorContexts.Commit) to update the value which in turn will fire CellValueChanged where you can then get the actual (i.e. correct) DataGridViewCheckBoxColumn value.
private void grid_CellContentClick(object sender, DataGridViewCellEventArgs e)
{
grid.CommitEdit(DataGridViewDataErrorContexts.Commit);
}
private void grid_CellValueChanged(object sender, DataGridViewCellEventArgs e)
{
// do something with grid.Rows[e.RowIndex].Cells[e.ColumnIndex].Value
}
Target .NET framework: 2.0
Small update.... Make sure you use EditedFormattedValue instead of value as I tried value but it never give right status that is checked/unchecked most of the site still use value but as used in latest c# 2010 express below is one way to access..
grdJobDetails.Rows[e.RowIndex].Cells[0].EditedFormattedValue
Also _CellValueChanged event suggested or used by few must be usable for some cases but if you are looking for every check/uncheck of cell make sure you use _CellContentClick else per my notice I see not every time _CellValueChanged is fired.. that is if the same checkbox is clicked over & over again it does not fire _CellValueChanged but if you click alternately for example you have two chekbox & click one after other _CellValueChanged event will be fired but usually if looking for event to fire everytime the any cell is check/uncheck _CellValueChanged is not fired.
Try hooking into the CellContentClick event. The DataGridViewCellEventArgs will have a ColumnIndex and a RowIndex so you can know if a ChecboxCell was in fact clicked. The good thing about this event is that it will only fire if the actual checkbox itself was clicked. If you click on the white area of the cell around the checkbox, it won't fire. This way, you're pretty much guaranteed that the checkbox value was changed when this event fires. You can then call Invalidate() to trigger your drawing event, as well as a call to EndEdit() to trigger the end of the row's editing if you need that.
I finally implemented it this way
private void dataGridView1_CellMouseClick(object sender, DataGridViewCellMouseEventArgs e)
{
if (e.ColumnIndex >= 0 && e.RowIndex >= 0)
{
if (dataGridView1[e.ColumnIndex, e.RowIndex].GetContentBounds(e.RowIndex).Contains(e.Location))
{
cellEndEditTimer.Start();
}
}
}
private void dataGridView1_CellEndEdit(object sender, DataGridViewCellEventArgs e)
{ /*place your code here*/}
private void cellEndEditTimer_Tick(object sender, EventArgs e)
{
dataGridView1.EndEdit();
cellEndEditTimer.Stop();
}
I had the same issue, but came up with a different solution:
If you make the column or the whole grid "Read Only" so that when the user clicks the checkbox it doesn't change value.
Fortunately, the DataGridView.CellClick event is still fired.
In my case I do the following in the cellClick event:
if (jM_jobTasksDataGridView.Columns[e.ColumnIndex].CellType.Name == "DataGridViewCheckBoxCell")
But you could check the column name if you have more than one checkbox column.
I then do all the modification / saving of the dataset myself.
"EditingControlShowing" event doesn't fire on checkbox value change. Because display style of the checkbox cell doesn't not change.
The workaround i have used is as below. (I have used CellContentClick event)
private void gGridView1_CellContentClick(object sender, DataGridViewCellEventArgs e)
{
if (string.Compare(gGridView1.CurrentCell.OwningColumn.Name, "CheckBoxColumn") == 0)
{
bool checkBoxStatus = Convert.ToBoolean(gGridView1.CurrentCell.EditedFormattedValue);
//checkBoxStatus gives you whether checkbox cell value of selected row for the
//"CheckBoxColumn" column value is checked or not.
if(checkBoxStatus)
{
//write your code
}
else
{
//write your code
}
}
}
The above has worked for me. Please let me know if need more help.
I found a simple solution.
Just change the cell focus after click on cell.
private void DGV_CellContentClick(object sender, DataGridViewCellEventArgs e)
{
if (e.ColumnIndex == "Here checkbox column id or name") {
DGV.Item(e.ColumnIndex, e.RowIndex + 1).Selected = true;
//Here your code
}
}
Don't forget to check if the column of your (ckeckbox + 1) index exist.
Every one of the CellClick and CellMouseClick answers is wrong, because you can change the value of the cell with the keyboard and the event will not fire. Additionally, CurrentCellDirtyStateChanged only fires once, which means if you check/uncheck the same box multiple times, you will only get one event. Combining a few of the answers above gives the following simple solution:
private void dgvList_CurrentCellDirtyStateChanged(object sender, EventArgs e)
{
if (dgvList.CurrentCell is DataGridViewCheckBoxCell)
dgvList.CommitEdit(DataGridViewDataErrorContexts.Commit);
}
private void dgvList_CellValueChanged(object sender, DataGridViewCellEventArgs e)
{
// Now this will fire immediately when a check box cell is changed,
// regardless of whether the user uses the mouse, keyboard, or touchscreen.
//
// Value property is up to date, you DO NOT need EditedFormattedValue here.
}
cellEndEditTimer.Start();
this line makes the datagridview update the list of checked boxes
Thank you.
I found a combination of the first two answers gave me what I needed. I used the CurrentCellDirtyStateChanged event and inspected the EditedFormattedValue.
private void dgv_CurrentCellDirtyStateChanged(object sender, EventArgs e)
{
DataGridView dgv = (DataGridView)sender;
DataGridViewCell cell = dgv.CurrentCell;
if (cell.RowIndex >= 0 && cell.ColumnIndex == 3) // My checkbox column
{
// If checkbox checked, copy value from col 1 to col 2
if (dgv.Rows[cell.RowIndex].Cells[cell.ColumnIndex].EditedFormattedValue != null && dgv.Rows[cell.RowIndex].Cells[cell.ColumnIndex].EditedFormattedValue.Equals(true))
{
dgv.Rows[cell.RowIndex].Cells[1].Value = dgv.Rows[cell.RowIndex].Cells[2].Value;
}
}
}
Use this code, when you want to use the checkedChanged event in DataGrid View:
private void grdBill_CellContentClick(object sender, DataGridViewCellEventArgs e)
{
grdBill.CurrentCell = grdBill.Rows[grdBill.CurrentRow.Index].Cells["gBillNumber"];
}
private void grdBill_CellEndEdit(object sender, DataGridViewCellEventArgs e)
{
calcBill();
}
private void calcBill()
{
listBox1.Items.Clear();
for (int i = 0; i < grdBill.Rows.Count - 1; i++)
{
if (Convert.ToBoolean(grdBill.Rows[i].Cells["gCheck"].Value) == true)
{
listBox1.Items.Add(grdBill.Rows[i].Cells["gBillNumber"].Value.ToString());
}
}
}
Here, grdBill = DataGridView1, gCheck = CheckBox in GridView(First Column), gBillNumber = TextBox in Grid (Second column).
So, when we want to fire checkchanged event for each click, first do the CellContentClick it will get fire when user clicked the Text box, then it will move the current cell to next column, so the CellEndEdit column will get fire, it will check the whether the checkbox is checked and add the "gBillNumber" in list box (in function calcBill).
Working with an unbound control (ie I manage the content programmatically), without the EndEdit() it only called the CurrentCellDirtyStateChanged once and then never again; but I found that with the EndEdit() CurrentCellDirtyStateChanged was called twice (the second probably caused by the EndEdit() but I didn't check), so I did the following, which worked best for me:
bool myGridView_DoCheck = false;
private void myGridView_CurrentCellDirtyStateChanged(object sender, EventArgs e)
{
if (!myGridView_DoCheck)
{
myGridView_DoCheck = true;
myGridView.EndEdit();
// do something here
}
else
myGridView_DoCheck = false;
}
Using the .EditedFormattedValue property solves the problem
To be notified each time a checkbox in a cell toggles a value when clicked, you can use the CellContentClick event and access the preliminary cell value .EditedFormattedValue.
As the event is fired the .EditedFormattedValue is not yet applied visually to the checkbox and not yet committed to the .Value property.
private void dataGridView1_CellContentClick(object sender, DataGridViewCellEventArgs e)
{
var checkbox = dataGridView1.CurrentCell as DataGridViewCheckBoxCell;
bool isChecked = (bool)checkbox.EditedFormattedValue;
}
The event fires on each Click and the .EditedFormattedValue toggles

Categories

Resources