I'm experiencing some weird behavior with the ComboBox.SelectionChangeCommitted event and am wondering if anyone has an explanation for it.
Somewhere in my event handler, I call MessageBox.Show. If I choose a new value in my ComboBox, and my code causes the MessageBox to pop up, I am seeing my selceted value get reverted back to its original value.
When debugging, I am seeing that the selected value is correct before MessageBox.Show. MessageBox.Show gives control back to the user until I click "Yes" or "No". After I have clicked one of the options, control returns to the debugger and the value of my ComboBox is reverted back to its original value before my change.
I am not programmatically setting the selected value elsewhere, so I'm at a loss as to why the value gets reverted. If the event handler does not pop the MessageBox, the selected does not get reverted.
Is it possible that the fact that I'm giving control back to the UI before I'm done handling the event has anything to do with it. If so, is there a clean way to get around it? Currently I'm capturing my selected value before I pop the MessageBox and then resetting it after, but I'd prefer to not have to resort to a "hack" to fix the issue.
The problem is likely that the act of displaying the message box causes the combo box drop-down menu to close, thus abandoning any uncommitted selection the user may have made.
It's basically the same thing as dropping down a combo box, highlighting an item in the list, and then pressing the Esc key. Notice that the highlighted item does not become the selected item because you never selected it before the combo box was dismissed. (You can try it easily yourself in the "Run" dialog.)
This is one of the many reasons why it's a bad idea to throw up message boxes all over the place (the other reasons include how visually jarring message boxes are to users, and that most of them don't even bother to read them anyway). Programmers who like to use message boxes as debugging aids are often bitten by this exact scenario when they try to debug UI code.
The solution is to either:
Defer validation until the entire form is committed/submitted, at which time you can show a message box without running the risk of abandoning any currently dropped-down combo boxes.
Find an alternative (i.e., non-modal) way of displaying the validation error. WinForms provides an ErrorProvider control that you can use for this purpose. The typical usage is showing a little warning or error icon next to the control with the invalid value; the user can hover over that icon to display a tooltip with more information about the exact error.
Or perhaps a combination of both approaches, allowing the user to get instant feedback but also ensuring that you never have to handle malformed input outside of the input form.
I was incorrect in my assumption that the subclass of ComboBox I was using did not add any relevant functionality. The issue ended up being due to a LostFocus event handler I was unaware of that caused the ComboBox to revert its value.
I could not recreate your issue using the code below which is essential what you are saying you are doing. The value in the combobox gets updated. You may get a better solution by posting the SelectionChangeCommitted code.
private void comboBox1_SelectionChangeCommitted(object sender, EventArgs e)
{
try
{
ComboBox cb = (ComboBox)sender;
string check1 = cb.Text;
MessageBox.Show("Messagebox check");
string check2 = cb.Text;
MessageBox.Show(check1 + "\n\n" + check2);
//check 1 and 2 show the old value. Once the method leaves then the value in the combobox is updated.
}
catch (Exception ex)
{
MessageBox.Show(ex.Message);
}
}
Related
Why does DataGridView raise CellValidating event upon simple navigation through arrow keys? How can I prevent it? Here is the key information about DataGridView state when it calls CellValidating:
EditMode = EditOnKeyStrokeOrF2
IsCurrentCellInEditMode = False
e.FormattedValue = [Same as the current value of the cell]
As you can see, user has not triggered any editing operation. He's just moving across the cells by pressing right-arrow key. One would not expect validation to occur at this point, right?
Note: Examining call stack shows that KeyDownevent triggers a CommitEdit call, which in turn raises OnCellValidating.
Like it or not, this is the way things are desigend to work. See MSDN on CellValidating:
Occurs when a cell loses input focus, enabling content validation.
And to make it complete MSDN on CellValidated:
Occurs after the cell has finished validating.
The most direct and readable solution is probably to put a line like this at the start of the CellValidating event:
if (!dataGridView1.IsCurrentCellDirty) return;
One reason for the designed behaviour could be the case where a user input is actually needed to create a valid cell value. Not your case, but still a conceivable requirement.
I have a small problem. I have a TextBox myTxt. I set the myTxt_Leave event to check the database if input value already exists. If value exists, I display a MessageBox and set myTxt.Focus(). That wont let user to leave this TextBox, until another value (which does not exist in the database) is input.
But here is the catch...I would like to allow user to click on Cancel button on the form even if the value does not change. Is that possible?
Hope someone understands what I wanted to tell.
Thank you for any help.
EDIT:
I decided to change the interface a little. I put red label under the textbox "Value already exists" and disabled the Submit button until the value is correct.
But still, I'm curious if solution for my previous problem is possible?
Instead of binding the event to the Leave interaction, just Highlight the box in red and disable the submit. When the when the error is resolved or the action is cancelled, clear the red / disabled submit button.
So I was asked to fix an issue with an old windows form utility that has been around a little while (least before any of my coworkers showed up). The form has a numericUpDown control that is databound. The issue was, when you clicked the up or down arrow the values would change and save OK however, if you just typed in a number and clicked save it wouldn't save. It was like the databinding never saw the change, so coming from a WPF background I guessed that changing the following
TaskDaysToComplete.DataBindings.Add("Value", taskTemplate, "DaysToComplete");
To this
TaskDaysToComplete.DataBindings.Add("Value", taskTemplate, "DaysToComplete", false, DataSourceUpdateMode.OnPropertyChanged);
would solve my problem and it did. You can now either type in a number or use the up/down arrows on the control to set the "Value" property.
My question is this, what was happening in the first place? I am guessing the default DataSourceUpdateMode was OnValidation but when does this happen and why was it OK for when using the up/down arrows but never seemed to happen when typing things in.
Thanks!
numericUD validation
validation is done on losing focus, so when you press the up/down key the textbox loses focus - triggering the validation routine.
when editing text you can make the control lose focus by clicking another control, this will cause it to validate.
the reason that the default is set to onValidate is that on value changed will cause it to validate on each character typed, which can be problematic both for performance and for correct validation.
I have a parent form with one DataGridView and a button. When the button is clicked, it opens a child window and when closed, goes back to the parent form. I want to validate the value being inputted in a cell of the DAtaGridView. I'm using CellValidated event and showing a message box whenever it inputs an invalid value. However, when I click on the button to open the child window and close it back, the DataGridView becomes just a white box with a diagonal cross, and a NullReferenceException shows.
Does anyone know what causes this issue? If not, what's the best way to validate a value of the cell and which event to put it in?
Just setup Visual Studio as described in this article: How to: Break When an Exception is Thrown. This way, you will be able to catch this exception in the debugger, and see where its roots are.
Whenever validating a cell in a DataGridView, you should use the CellValidating event.
You can get the data using the DataGridViewCellValidatingEventArgs and set the Cancel property to True if it is invalid data. This is gonna prevent the CellValidated event from being raised and should give the focus back to the given cell.
If this doesn't help, can you provide some code and show us where the exception occured?
I have been binding textboxes in a winform with C# to a dataset. Whenever the data doesn't validate with what the database except it silently forces the focus to remain on the textbox. How can I catch the validation error and tell the user about it (and free the focus)? The BindingSource event OnDataError isn't fired.
I had a similar problem once. The focus remained in the textbox which was binded to some numeric database field when the user modified text in a textbox and then deleted it so the text property was an empty string. I solved it with something like:
textbox.DataBindings["Text"].NullValue = "";
It solved the problem for empty inputs. I don't know if it would be of any use in your case, but I'd be also interested in more general solution.
Here's also some related question on SO:
Data-bound TextBox: can't exit
Never rely on just what "Visual studio has done for me" if you don't fully understand what it's doing. I would strongly urge you to take the time and figure out how to do what it is you want to do all by yourself (meaning without designer generated code). To get you started, there are some events on the TextBox that can help you out. Start here:
http://msdn.microsoft.com/en-us/library/system.windows.forms.control.validated.aspx
Specifically the validating and validated events should be what you're looking for.