My C# winform has a datagridview and when I clicked update button, what code should I put to check whether any cells had been edited?
I just need to have a true or false.
Thanks.
===========================================================================
My existing codes:
#region Edit Records
private void InProSysAdministrationEventsUpdateButton_Click(object sender, EventArgs e)
{
if (MessageBox.Show("Please Click Ok to Edit the Events", "Confirmation", MessageBoxButtons.OKCancel) == DialogResult.OK)
{
ManipulateData.UpdateData(connectionString, tblconn, tblscmd, tbldataadaptor, tbldatatable, cmbuilder, "usp_readallevents", readalleventsdataGridView);
}
}
#endregion
I need to do the following:
1) user click on edit
2) system check whether any cell had been edited
3) if no cell edited, it will messagebox.show("No Changes Done.")
4) else, it will update the database.
Have you taken a look at the DataGridView.CellValueChanged Event? MSDN
Would be fairly simple to just write a handler for this and set a flag, or perform whatever action you want.
An example of how you might go about performing this would be:
protected override void OnLoad(EventArgs e)
{
myDataGridView.CellValueChanged += new DataGridViewCellEventHandler(
myDataGridView_CellValueChanged);
}
private void myDataGridView_CellValueChanged(
object sender, DataGridViewCellEventArgs e)
{
//some very crude examples of actions you might want to perform when the event handler is triggered.
myObject.update();
//or something else like
myObject.isUpdatable = true;
}
With regards to point number 3, a msgbox is probably not the best way to inform a user of a non-critical event. It is likely that they are already going to know that they haven't entered any information, and you can provide this feedback less anoyying ways by perhaps flagging required cell, or whatever. Food for thought.
In the future, I'd recommend searching MSDN for the class you are working with, and searching for the type of event, method, or property you are looking for, and see if anything matches. There are plenty of useful examples available as well.
int x=0;
private void dataGridView1_CellEndEdit(object sender, DataGridViewCellEventArgs e)
{
x = 1;
}
if(x==1) //this means that gridView has been updated
Related
I have a DataGridView with several columns of TextBoxes. I need to capture the event where they are done entering data, and are exiting the box (via Tab, Enter, Mouse click elsewhere, etc)
I have searched SO and Google, and it seems like you have to build an event from scratch. I've tried multiple variations on what I have found since I can't seems to find one that fits with my particular needs.
I've been at this for longer than I care to admit and I need help.
Here is what I have...
// Select DataGridView EditingControlShowing Event
Private void gridData_EditingControlShowing(object sender, DataGridViewEditingControlShowingEventArgs e) {
e.Control.TextChanged += new EventHandler(textBox_TextChanged);
Control cntObject = e.Control;
cntObject.TextChanged += textBox_TextChanged;
}
// TextBox TextChanged Event
Private void textBox_TextChanged(object sender, EventArgs e) {
// Checks to see if the AddlQty field was altered
if (gridData.Columns[e.ColumnIndex].Name == "AddlQty") {
// Validate Entry
if (e.Text is Not numeric) {
MessageBox.Show("Entry Not Valid, Only Numeric Values Accepted");
} else {
CalcFinalQty(e.RowIndex);
}
}
}
For the record, the code does NOT work, the validation is quasi code and I'm getting an error in the function heading. The important part for me is the
if (gridData.Columns[e.ColumnIndex].Name == "AddlQty"){ }
I just need help getting to that point.
I'm developing a C# Windows Form program and I've implemented a DataGridView on it. Now, after setting the data source, when I click the top left button on the datagridview, it selects all rows, just like Microsoft Excel. However, I dynamically hide and show rows on it, and after clicking that button I realized that it also selects the invisible ones. I don't want to implement "SelectionChanged" event because I constantly select some rows and normally I can't select the invisible ones. Only this button selects it. I'm looking for an event like this:
datagridView1_SelectAllClicked(object sender, EventArgs e)
{
// do stuff
}
Something like this will also work since I don't have to check all selections:
dataGridView1_SelectionChanged(object sender, EventArgs e)
{
if(dataGridView1.IsSelectAllCells())
{
// do stuff
}
}
If I have to, I will add the event to deselect the invisible rows, but I prefer some solution like the first one. Any advices? Thanks in advance.
Edit: I'm checking "dataGridView1.SelectedRows" property on button clicks only, not after the selection was made. So, some function that I can implement to button click events will also solve my problem.
The DataGridView class provides the AreAllCellsSelected methode:
Returns a value indicating whether all the DataGridView cells are currently selected. (MSDN)
With that we can get a solution like your second one:
private void dataGridView1_SelectionChanged(object sender, EventArgs e)
{
DataGridView view = sender as DataGridView;
if (view.AreAllCellsSelected(true))
{
foreach (DataGridViewRow row in view.Rows)
{
//deselect all invisible rows
if (!row.Visible)
row.Selected = false;
}
}
}
I've managed to solve it finally, the solution was simpler than I expected.
private void RemoveInvisibleSelection()
{
if (dataGridView1.SelectedRows.Count == dataGridView1.Rows.Count)
{
for (int i = 0; i < dataGridView1.SelectedRows.Count; i++)
if (!dataGridView1.SelectedRows[i].Visible)
dataGridView1.SelectedRows[i--].Selected = false; // decreased the index value since SelectedRows property loses an object
}
}
I'm trying to build a simple interface that allows users to drop files into a listBox to add them to a process, and to drag them out to remove them. Everything is working fine, but I'd like to add one feature to make it just a tad more sophisticated.
Right now, I have the removal of the item tied to the DragLeave event, which means that as soon as the mouse leaves the box, the item is removed. But I'd like for users to be able to change their minds. In other words, if they realize they're dragging the wrong file out, I'd like them to be able to move the mouse back into the listBox and release the mouse to cancel the action. I'm thinking that means I need to be able to capture the MouseUp event instead of the DragLeave event. But that hasn't been successful so far.
Below is the code I'm currently using for removing files dragged out. How can I modify to keep the files from being removed form the list until the user lets the mouse button go?
private void listBox1_MouseDown(object sender, MouseEventArgs e)
{
if (listBox1.Items.Count == 0)
{
return;
}
int index = listBox1.IndexFromPoint(e.X, e.Y);
string s = listBox1.Items[index].ToString();
DragDropEffects dde1 = DoDragDrop(s, DragDropEffects.All);
}
private void listBox1_DragLeave(object sender, EventArgs e)
{
ListBox lb = sender as ListBox;
lb.Items.Remove(lb.SelectedItem);
}
Edit 2013/05/16
The comments and answers so far have been useful, but I realize my question isn't clear enough. In this case, I'm displaying a dialog separate from the parent form that is basically as big as the listBox. When someone drags a file out of the list, they're dragging it off the form completely. Have I backed myself into a corner by doing this? I recognize I'm making it harder than it has to be, but I'd still like to see how it would work if it's possible.
Here's a fairly quick hack approach to gaining the functionality you want:
public object lb_item = null;
private void listBox1_DragLeave(object sender, EventArgs e)
{
ListBox lb = sender as ListBox;
lb_item = lb.SelectedItem;
lb.Items.Remove(lb.SelectedItem);
}
private void listBox1_DragEnter(object sender, DragEventArgs e)
{
if (lb_item != null)
{
listBox1.Items.Add(lb_item);
lb_item = null;
}
}
private void listBox1_MouseDown(object sender, MouseEventArgs e)
{
lb_item = null;
if (listBox1.Items.Count == 0)
{
return;
}
int index = listBox1.IndexFromPoint(e.X, e.Y);
string s = listBox1.Items[index].ToString();
DragDropEffects dde1 = DoDragDrop(s, DragDropEffects.All);
}
private void Form1_DragDrop(object sender, DragEventArgs e)
{
lb_item = null;
}
Every time the user drags an item out of the box, it's saved temporarily until the user drops it somewhere else or mouses down on a new item in the list.
Note the important part of this is detecting when and where the user let's go of that mouse, which is the rationale behind handling the DragDrop event of Form1, the parent of listBox1.
Depending on the sophistication and density of the rest of your layout, where you handle DragDrop could be much different for you. This is why it's kind of "hacky", but it's also quite simple. It shouldn't matter, though, where or how many times you null lb_item since it pertains only to that specific ListBox.
I suppose another way to do it would be to track the user's mouse states and act accordingly, which may be more appropriate for you if it's inconceivable to handle a lot of DragDrop stuff.
EDIT: If you wanted to be REAL thorough, you could enumerate through every control of the base form using foreach and programmatically append a handler for the DragDrop event to that control, then remove it when done... but that may be getting a little nutty. I'm sure someone has a better approach.
Let's say we have a Win32 form with a Save toolbar button and some sontrols like a CheckBox are on the form, now we write a one line code for onchange event of checkbox to enable/disable the Save button. Let's say checkbox is selected at first, Save button disabled, now de-select the checkbox, Save button becomes enabled...now select the checkbox again Save button is still enabled...Same for a TextBox for example. Let's say its text is "Hi"...change it to "Hi Bye" , Save is enabled...change it BACK to "Hi" as it was, Save remains enabled...
Is there a model we can use to prevent these wrong enabling/disabling of save button?
You need to write some IF - ELSE code in the CheckedChanged event of the Checkbox. Check what is the current state by inspecting the Checked proeprty of the control (checkbox) ,If yes set the Enabled proeprty of the Button to true, else false.
private void checkBox2_CheckedChanged(object sender, EventArgs e)
{
if (checkBox2.Checked)
button1.Enabled = true;
else
button1.Enabled = false;
}
Assuming checkBox2 is the name of the Checkbox and button1 is the name of the Save button.
You can use the same IF ELSE logic for other controls also. To Set the Value of the Textbox, Use the Text property
TextBox1.Text="I am gonna try something now"l
EDIT : As comecme suggested, If you only want to enable/disable button based on the checbox, It can be done in one line instead of the IF else block like this
button1.Enabled=checkBox2.Checked
You could store the last saved state, and compare the current state to it whenever it changes, to see if they're identical. If so, disable the button.
If these comparisons are expensive, you could make this more efficient, by calculating a hash value over all of the fields that need to be saved, and only doing the proper comparison if the hash of the last saved state matches the hash of the current state.
I prefer to put all my control state checking and setting into a single method:
private void UpdateControls()
{
saveButton.Enabled = checkBox1.Checked;
otherButton.Visible = checkBox2.Checked && textBox.Text.Length > 0;
}
private void checkBox1_CheckedChanged(object sender, EventArgs e)
{
UpdateControls();
}
private void checkBox2_CheckedChanged(object sender, EventArgs e)
{
UpdateControls();
}
private void textBox_TextChanged(object sender, EventArgs e)
{
UpdateControls();
}
This means you just have one place in which to check and set the state, and makes it much easier to understand what is going on, especially when you have complex forms. I also prefer boolean expressions rather than if statements when assigning boolean variables, because it caters for both true and false without having to write a separate else statement (which may be forgotten).
I don't get where you're going with your checkbox, but I would use a Boolean variable:
private Boolean _canSave = false;
private Boolean CanSave
{
get { return _canSave; }
set
{
_canSave = value;
MenuSave.Enabled = value;
}
}
public void MenuSave_Click()
{
Save();
}
private void Save()
{
// do your thing
CanSave = false;
}
public void TextBox_TextChanged()
{
CanSave = true;
}
This won't account for disabling the saving menu when you revert the text back to its original. If you want that, you'll have to store the text in the Save() method in a private variable, and compare that to the current text on every TextBox_TextChanged() to determine whether a change compared to the original (i.e. since last save) has occurred.
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