Post Updated: handle Escape key at Dialog level, not just for txtName control.
I would simplify the application, by dropping the Clear and Save buttons,and allow the Framework to setup the text boxes.
These are the changes I would recommend:
private void AddressBook_Load(object sender, EventArgs e)
{
// Read in and fill the datagrid.
this.ReadAddressBookXML();
// If no entries in address book, set for new address
if (bsAddressBook.Count == 0)
{
SetForNewAddress();
}
}
private void btnAddNew_Click(object sender, EventArgs e)
{
SetForNewAddress();
}
// Drop btnSave_Click & btnClear_Click event handlers
void txtName_Validating(object sender, CancelEventArgs e)
{
txtName.Text = txtName.Text.Trim();
string errorMessage = "";
if (txtName.Text.Length == 0)
{
errorMessage = "Please enter a name";
}
/*
else
{
// Optional - do additional validation, such as checking for duplicate name
}
*/
if (errorMessage.Length != 0)
{
errorProvider.SetError(txtName, errorMessage);
e.Cancel = true;
}
}
void txtName_Validated(object sender, EventArgs e)
{
//End editing ofnew record
bsAddressBook.EndEdit();
// Re-allow adding / deleting of records
btnAddNew.Enabled = btnDelete.Enabled = true;
}
void bsAddressBook_CurrentChanged(object sender, EventArgs e)
{
btnAddNew.Enabled = btnDelete.Enabled = true;
}
private void AddressBook_FormClosing(object sender, FormClosingEventArgs e)
{
// Ensure changes to current record are kept
bsAddressBook.EndEdit();
//Save address book
WriteAddressBookXML();
}
protected
override bool ProcessDialogKey(Keys keyData)
{
// Allow user to cancel edit of new / current record
if (keyData == Keys.Escape)
{
this.ActiveControl.CausesValidation = false;
bsAddressBook.CancelEdit();
this.ActiveControl.CausesValidation = true;
}
return base.ProcessDialogKey(keyData);
}
// Helper functions
private void SetForNewAddress()
{
bsAddressBook.AddNew();
btnAddNew.Enabled = btnDelete.Enabled = false;
txtName.Focus();
}
NOTE: I used an ErrorProvider to display validation erors. This shows a circular red icon next to the text box with the error, with a ToolTip showing the error message (hover over icon with mouse cursor). To add the ErrorProvider, drag the component from the Toolbox to your form.
You'll also need to setup the missing event handlers in the Designer (txtName - Validating & Validated, bsAddressBook -CurrentChanged and AddressBook -FormClosing).
So, on clicking the Add button, the Framework will automatically clear the textboxes (as you found). I've also disabled the Add & Delete buttons to indicate useris setting up a new entry.
When the user has at least entered a name, which is the minimum I've assumed is required for a record, I end editing of the record and re-enable the buttons.
If the user clicks on another record, the current record is validated (name must not be blank) and if successful, changes made to the record are saved by the Framework and the newly selected record is shown.
Whilst editing a record, the user can press Esc to cancel changes. If they were creating a new record and they haven't yet entered a valid name and moved to another text box, the record is discarded by the Framewok.
The xml file is only updated when the form is closed as upadting the file after every record edit is most likely overkill.
The one extra thing you might want to do is to add Validated event handlers for the other text boxes and call EndEdit on the BindingSource.The DataGrid row would thenbe updated as they move from text box to text box.