Im working with errorprovider in a c# winforms application.
Now I want to have a "double" validation. Once on the textfields directly, so the user sees that he has made some errors, and once on the button itself. So when there are still errors, the "save" button will keep greyed out or "disabled".
Because I don't want to block my user when he is making an error, and I want him to be able to make the changes whenever he wants im using the event "leave" or on focus lost. This because otherwise I noticed you cannot go to another field, until you changed your error.
So, now the code:
private void txtFirstname_Leave(object sender, EventArgs e)
{
if (!InputChecks.IsFilledIn(txtFirstname.Text))
{
errorProvider1.SetError(txtFirstname, "Firstname needs to be filled in!");
isValidated = false;
}
else
{
errorProvider1.SetError(txtFirstname, "");
isValidated = true;
}
}
So far, so good. The error provider works correctly and my user can edit whenever he wants.
public void setSaveButton()
{
if (isValidated == true)
{
btnSave.Enabled = true;
}
else
{
btnSave.Enabled = false;
}
}
bool isValidated;
private void btnSave_Click(object sender, EventArgs e)
{
if (isValidated == true)
{
employeePresenter.addEmployee(txtFirstname.Text, txtLastname.Text, txtUsername.Text, txtPassword.Text);
}
}
This was still okey in my head. BUT, as I give the ability to the user to change the issues whenever they want, this doesn't work. I tried to put the method "setSaveButton()" under "isvalidated" but this is not working either. Because of the focus lost.
Anyone has a better idea for this? I have been looking on google and the only things i found was a single validation with the errorprovider, or the event validating. But these events don't allow users to edit their errors whenever they want. It blocks them into one particular text field.
You don't need to make the save button disabled. It's enough to check ValidateChildren method of your form and if it returned false, it means there is some validation error. To use this approach you should remember to set e.Cancel = true in Validating event of the control when you set an error for control.
Also to let the user to move between controls even if there is an error, set AutoValidate property of your Form to EnableAllowFocusChange in designer or using code:
this.AutoValidate = System.Windows.Forms.AutoValidate.EnableAllowFocusChange;
Code for Validation:
private void txtFirstname_Validating(object sender, CancelEventArgs e)
{
if (string.IsNullOrEmpty(this.txtFirstname.Text))
{
this.errorProvider1.SetError(this.txtFirstname, "Some Error");
e.Cancel = true;
}
else
{
this.errorProvider1.SetError(this.txtFirstname, null);
}
}
private void btnSave_Click(object sender, EventArgs e)
{
if (this.ValidateChildren())
{
//Here the form is in a valid state
//Do what you need when the form is valid
}
else
{
//Show error summary
}
}
Related
I have the following code:
private void myTextBox_Validating(object sender, CancelEventArgs e)
{
if (some condition)
{
e.Cancel = true;
errorProvider.SetError(myTextBox, "Error occurred");
return;
}
this.errorProvider.SetError(this.myTextBox, null);
}
And the following Button_click code to trigger all Validating events:
private void saveData_Click(object sender, EventArgs e)
{
if (!this.ValidateChildren())
{
return;
}
}
It did validate correctly. However, I can't seem to click anywhere besides myTextBox when I click that texbox without changing its invalid value. Can I disable that "locking to your error until you change it" feature?
You can control the behaviour of your controls, whether they are allowed to lose focus while having invalid data or not.
On your form you can set the following property:
this.AutoValidate = AutoValidate.EnableAllowFocusChange;
For details and other ways of getting a similar effect, please have a look at the docs
I am using a datagradview and I am wanting to prompt the user to save the current row before moving off I have been trying to use the following event but I seem to be in a circular loop when I hit my save event.
private void dgStock_SelectionChanged(object sender, EventArgs e)
{
if (isDirty == true)
{
isSavedFromRow = true;
btnSaveDetails_Click(sender, e);
isDirty = false;
}
}
The problem with the selection changed event is this happens once the row has changed so the user could think their saving the new row and not the current row.
I also seem to be caught in a circular loop some how has the messagebox box is getting fired numerious times I am only setting the isDirty to true if the user enters key down on my textboxes.
if (isDirty == true)
{
DialogResult _result = MessageBox.Show("Are you sure you wish to upate Live Product Information", "Save Changes", MessageBoxButtons.YesNo, MessageBoxIcon.Information);
if (_result == DialogResult.Yes)
{
updateStock();
_trackChanges.Clear();
isDirty = false;
}
}
This is me setting my dirty flag on key down felt this was best way to avoid the problem I seem to be having.
private void txtDescription_KeyDown(object sender, KeyEventArgs e)
{
isDirty = true;
btnSaveDetails.Enabled = true;
}
Your code sample suggests that your save stuff is defined in your save button click. If you change your structure to something like this
private void SaveClick(object sender, EventArgs e)
{
DoSaveStuff();
}
private void DoSaveStuff()
{
// Do your save stuff
}
i.e. pull your save stuff out into a method. You can call DoSaveStuff() whenever you need to save, e.g.
private void SelectionChanged(object sender, EventArgs e)
{
// Do stuff
if (condition)
{
DoSaveStuff();
}
}
The advantage of this approach is you're capturing the aspect of the behaviour you're interested in - the save stuff - rather than the whole button click. Furthermore, you click a button to save, your application doesn't, it simply saves in certain circumstances, e.g. when you click a button or when something changes.
As MSDN says the SelectionChangedEvent occurs whenever the selection has changed. So, whenever this happens you could check your original selection to see if it has changed and then save if it has. Maybe doing something like this
private void SelectionChanged(object sender, EventArgs e)
{
bool hasContentsChanged = // determine if your content has changed
if (hasContentsChanged)
{
DoSaveStuff();
}
}
An advantage of this approach is that you'd only have to save if it really had changed, i.e. if the original text != new text, rather than in all cases.
To make sure that the user name input is valid, I added such callback method to do the verification:
Regex UserNameRE = new Regex(#"^[a-zA-Z]\w*$");
//being called when input box is not focused any more
private void UserNameInput_Leave(object sender, EventArgs e)
{
//pop up a warning when user name input is invalid
if (!UserNameRE.IsMatch(UserNameInput.Text))
{
MessageBox.Show("Invalid User Name!");
this.UserNameInput.Text = "";
this.UserNameInput.Focus();
}
}
The method will be called when user finished their inputting(the method is bounded with the event-"leaving the input box"). It works when user left a invalid User_Name and begin to enter a password.
But it also works when user click another tab, e.g. the Register tab. I don't want this happen. Because the user obviously don't wanna login anymore if he clicks "Register" tab, and my C# app shouldnot pop up a warning box and force them inputting a valid user name again.
How can the C# tell the difference of such 2 situations? It should be easy if I know which object is being clicked.
You will have source of event in object sender in UserNameInput_Leave event.
private void UserNameInput_Leave(object sender, EventArgs e)
{
//sender is source of event here
}
Here's an option:
private void UserNameInput_Leave(object sender, EventArgs e)
{
if (sender.GetType() != typeof(TextBox))
{
return;
}
TextBox tBox = (TextBox)sender;
//pop up a warning when user name input is invalid
if (!UserNameRE.IsMatch(UserNameInput.Text) && tBox.Name == UserNameInput.Name)
{
MessageBox.Show("Invalid User Name!");
this.UserNameInput.Text = "";
this.UserNameInput.Focus();
}
}
I am not sure if there's a right solution for this particular scenario here.
When you add a handler to validate your control on mouse leave, definitely it will be executed first regardless you clicked on another control within the tab or another tab itself.
This normal flow can't be ignored easily. It must be possible by hanlding the message loop yourself but the event based flow, first leave focus, and selected index change (selecting) event will be fired. I would suggest you not to disturb the flow as the validation is client side and pretty fast. Instead of messagebox, I would recommend you to use ErrorProvider and attach to the control whenever required. Also messagebox is quite disturbing and as per your code, you're forcefully making it focus to the textbox again.
How about the following code?
public partial class Form1 : Form
{
ErrorProvider errorProvider = new ErrorProvider();
public Form1()
{
InitializeComponent();
textBox1.Validating += new CancelEventHandler(textBox1_Validating);
}
private void textBox1_Leave(object sender, EventArgs e)
{
textBox1.CausesValidation = true;
}
void textBox1_Validating(object sender, CancelEventArgs e)
{
Regex UserNameRE = new Regex(#"^[a-zA-Z]\w*$");
if (!UserNameRE.IsMatch(textBox1.Text))
{
errorProvider.SetError(this.textBox1, "Invalid username");
}
}
}
I want to put a validation that the user always enters a value in the textbox before submiting the form. But the check that I have put allows user to enter white spaces and continue submitting the form.
So, how to put the check so that the user in not able to submit the form if there are only white spaces in the textbox.
You can make your own custom validation function. This may be very naive, but somehow it will work.
private bool WithErrors()
{
if(textBox1.Text.Trim() == String.Empty)
return true; // Returns true if no input or only space is found
if(textBox2.Text.Trim() == String.Empty)
return true;
// Other textBoxes.
return false;
}
private void buttonSubmit_Click(object sender, EventArgs e)
{
if(WithErrors())
{
// Notify user for error.
}
else
{
// Do whatever here... Submit
}
}
in NET4.0 there is a nice function
if(string.IsNullOrWhiteSpace(textBox1.Text))
{
//raise your validation exception
}
else {
//go to submit
}
It can be easily be done using error provider here is the code.Error Provider you can find in your toolbox.
private void btnsubmit_Click(object sender, EventArgs e)
{
if (string.IsNullOrEmpty(txtname.Text))
{
txtname.Focus();
errorProvider1.SetError(txtname, "Please Enter User Name");
}
if (string.IsNullOrEmpty(txtroll.Text)) {
txtroll.Focus();
errorProvider1.SetError(txtroll, "Please Enter Student Roll NO");
}
}
Here is output image
Is there a shortcut in validating fields in winforms? For example a particular textBox is required to be filled up before saving a record. What I always do is I check first all the required fields programatically before saving. Example:
protected bool CheckFields()
{
bool isOk = false;
if(textBox1.Text != String.Empty)
{
isOk = true;
}
return isOk;
}
private void btnSave_Click(object sender, EventArgs e)
{
if(CheckFields())
{
Save();// Some function to save record.
}
}
Is there a counter part of Validator in ASP.Net in winforms? Or any other way around...
Here is one approach:
private List<Control> m_lstControlsToValidate;
private void SetupControlsToValidate()
{
m_lstControlsToValidate = new List<Control>();
//Add data entry controls to be validated
m_lstControlsToValidate.Add(sometextbox);
m_lstControlsToValidate.Add(sometextbox2);
}
private void ValidateSomeTextBox()
{
//Call this method in validating event.
//Validate and set error using error provider
}
Private void Save()
{
foreach(Control thisControl in m_lstControlsToValidate)
{
if(!string.IsNullOrEmpty(ErrorProvider.GetError(thisControl)))
{
//Do not save, show messagebox.
return;
}
}
//Continue save
}
EDIT:
For each control in m_lstControlsToValidate you need to write the validation method that would be fired in Validating event.
ErrorProvider.GetError(thisControl) will return some errortext or emptystring. Empty string means the control is fine. Else the control contains some error and we abort the save operation.
We do this on all the controls in m_lstControlsToValidate. If all controls are error free we continue with save else abort.
Not really, in Win Form you should use the Control.Validating Event for validation when user is working on the form. But for saving validation You have write code that check that all data are correctly inserted by user. For instance you can create a mandatory TextBox, and iterate over all form controls looking for this type of control and check that user has inputed some text.
Use a validation control. They are the best thing to use.
Also,
protected bool CheckFields()
{
bool isOk = false;
if(textBox1.Text != String.Empty)
{
isOk = true;
}
return isOk;
}
Can be shorterned considerably to:
protected bool CheckFields()
{
return textBox1.Text != String.Empty;
}