I have a Windows forms application in C# and I have a form that when the user closes it I ask, "do you want to save the changes"? How can I get the changes in my form? Here is some code:
public partial class DepartEdit : Form
{
string _nameDep; //This variavel get value textbox when form load
{
InitializeComponent();
}
private void DepartamentEdit_FormClosing(object sender, FormClosingEventArgs e)
{
if (txtNameDepart.Text != _nameDep && codDepartament > 0)//Here i compare
{
DialogResult dlg = MessageBox.Show("Save changes?", "Question", MessageBoxButtons.YesNo);
if (dlg == DialogResult.Yes)
{
saveDepart(); // Metod save depart
e.Cancel = false;
}
if(dlg ==DialogResult.No)
{
e.Cancel = false;
}
}
}
There are a lot of textboxs and combo boxes? Is there any other way to get the changes in the form?
A lot will depending on where the information is held.
It you are using DataBinding you should be just monitoring the listChanged event or calling dataTable.GetChanges() if you are using a DataTable.
If the information comes from a class the implements ICloneable and IComparable, then you can take just take a backup copy when intialising the form (and after saving) and when closing you prepare you class for saving and compare it with the original.
Otherwise you can do something like
Declare a private variable
private bool requiresSaving =false;
Declare an event
private void SomethingChanged(object sender, EventArgs e)
{
requiresSaving = true;
}
Hook up this event to the various changed events, eg
this.txtNameDepart.TextChanged += new System.EventHandler(this.SomethingChanged);
(The actual event is sometimes called something different , eg ValueChanged, SelectedIndexChanged , but they can all point to SomethingChanged unless you need a particular event to do something else.)
Check this variable when you are closing the form
private void DepartamentEdit_FormClosing(object sender, FormClosingEventArgs e)
{
if (requiresSaving)
{
....
You also need to set requiresSaving false in the saveDepart method.
Alternatively I have seem code where, when the control is being intialised, the tag value is also set, and the formclosing event loops through each control and compares the original values (in the tag object) with the current values.
Create a string (or string[] I guess) within the Form_Load event and initialise them with the values present when the form first opens.
eg
string oName = nameTextBox.Text;
string oCompany = companyComboBox.Text;
Then during the Form_Closing() event you can check these against the current values
private void Contact_FormClosing(object sender, FormClosingEventArgs e)
{
if (oName!=nameTextBox.Text||oCompany!=companyComboBox.Text)
{
DialogResult result = MessageBox.Show("Would you like to save your changes",
"Save?",
MessageBoxButtons.YesNoCancel,
MessageBoxIcon.Stop);
if (result == DialogResult.Yes)
{
SaveFormValues();
}
else if (result == DialogResult.Cancel)
{
// Stop the closing and return to the form
e.Cancel = true;
}
else
{
this.Close();
}
}
}
Loop the forms controls, and add your event watchers. These events will call a function in the form that will keep a Hashtable or some other various collection up to date w/ the status of any changes to a particular control.
like I have, Hashtable changes;
then each time my event is called, i say, Add Control.Name, and then a change status, whatever you want. Then you have a list of controls that have been updated.
I can go into more detail if need be, hopefully this will get you started.
Well I think the theory is good. There are some problems with the implementation.
if (dlg == DialogResult.Yes)
{
saveDepart(); // Metod save depart
e.Cancel = false;
}
if(dlg ==DialogResult.No)
{
e.Cancel = false;
}
I think it would be a lot similier to write this:
if(dlg == DialogResult.Yes)
{
saveDepart();
}
// You don't need to change e.Cancel to false here unless you set it to true previously.
It's simple
Declare a global variable count=0
Now on your form u might already have a Save button so just increment count on save button click event
Now on form close event just check for the value of count if it's 0 ask user to save info either by reminding by message box
If it's 1 or greater than1 just close the form
I hope u get it
Related
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.
I would like to ask the user when he/she clicks the closebutton: save the file, discard the changes, or go back IF the RichTextBox content changed. Like Windows Notepad or any other text editor does. How could I do that?
You need to read about events and how they work. In this case, you are interested in the TextChanged event of the RichTextBox and the FormClosing event of the form.
TextChanged Event : MSDN
The TextChanged event is raised whenever the contents of the textbox are modified. One way to track changes in the textbox is simply to use a boolean value. Be sure to set it to false when you are loading data into the textbox. Then, when the user changes the text the TextChanged event will fire and you can set the _textChanged (in the example below) value to true.
Similarly, making use of the FormClosing event allows you to react to a user attempting to close the form.
FormClosing Event : MSDN
This event passes a FormClosingEventArgs value e that allows you to cancel the closing of the form (in this case if the user selects to cancel when prompted about the text having been changed). It also allows you to perform any other action before the form is closed.
To create the message dialog you can use an appropriate overload of MessageBox.Show - this function returns a DialogResult indicating which of the buttons the user clicked. This allows you to take different actions depending on the selection the user made.
MessageBox.Show : MSDN
If you don't know how to connect these events, then I suggest you read through some of the basic documentation and examples. This is pretty elementary stuff that you will need to understand to get much of anything done in C#. The examples here are winforms since you have not indicated otherwise.
This is a trivial example :
public partial class Form1 : Form
{
private bool _textChanged;
public Form1()
{
InitializeComponent();
// load data to richtextbox, then ....
_textChanged = false;
}
private void richTextBox1_TextChanged(object sender, EventArgs e)
{
_textChanged = true;
}
private void Form1_FormClosing(object sender, FormClosingEventArgs e)
{
if (_textChanged)
{
DialogResult rslt = MessageBox.Show("save changes?", "some caption",
MessageBoxButtons.YesNoCancel);
if (rslt == DialogResult.Yes)
{
// save changes and exit
}
else if (rslt == DialogResult.Cancel)
{
e.Cancel = true;
// cancel close, return to form
}
// else do not save and continue closing form
}
}
}
If the user wants to exit the application by clicking on the exit icon or by ALT+F4, I'd like to make a dialog box questioning the user if he/she is really sure about exiting.
How do I capture this event before the application is actually closed?
Check out the OnClosing event for the form.
Here is an extract from that link actually checks for a change on a text field and prompts a save:
private void Form1_Closing(object sender, System.ComponentModel.CancelEventArgs e)
{
// Determine if text has changed in the textbox by comparing to original text.
if (textBox1.Text != strMyOriginalText)
{
// Display a MsgBox asking the user to save changes or abort.
if(MessageBox.Show("Do you want to save changes to your text?", "My Application",
MessageBoxButtons.YesNo) == DialogResult.Yes)
{
// Cancel the Closing event from closing the form.
e.Cancel = true;
// Call method to save file...
}
}
}
You can change the text to suit your needs, and then also I think you might want to switch the DialogResult.Yes to DialogResult.No based on your text.
Here is some modified code just for you:
private void Form1_Closing(object sender, System.ComponentModel.CancelEventArgs e)
{
if(MessageBox.Show("Are you sure you want to quit?", "My Application", MessageBoxButtons.YesNo) == DialogResult.No)
{
e.Cancel = true;
}
}
You should subscribe to the Form_Closing event
Post a dialog box there, and if user abort the closing set the FormCloseEventArgs.Cancel to true.
For example in the Form_Load or using the designer, subscribe the event
Form1.FormClosing += new FormClosingEventHandler(Form1_Closing);
....
private void Form1_FormClosing(Object sender, FormClosingEventArgs e)
{
DialogResult d = MessageBox.Show("Confirm closing", "AppTitle", MessageBoxButtons.YesNo );
if(d == DialogResult.No)
e.Cancel = true;
}
Depending on the situation is not always a good thing to annoy the user with this kind of processing.
If you have valuable modified data and don't want the risk to loose the changes, then it is always a good thing to do, but if you use this only as a confirm of the close action then it's better to do nothing.
You can handle the Form_Closing or Form_Closed events for this.
In Visual Studio click the lightning bolt icon and scroll down to these events in the form properties list. Double click on the one you want and it will hook up the event for you.
Read msdn sample: http://msdn.microsoft.com/en-us/library/system.windows.forms.form.closing.aspx
Is this just one form? If so, you might want to use the FormClosing event, which allows you to cancel it (show the dialog, then set CancelEventArgs.Cancel to true if the user chooses to cancel closing).
If you're talking about windows forms, should be enough to catch your MainWindow's
FormClosing event and in case you want prevent closing, just set the argument of the event handler got fired, to true.
Example:
private void Form1_Closing(object sender, System.ComponentModel.CancelEventArgs e)
{
if(MessageBox.Show("Do you really want to exit?", "My Application",
MessageBoxButtons.YesNo) == DialogResult.No){
// SET TO TRUE, SO CLOSING OF THE MAIN FORM,
// SO THE APP ITSELF IS BLOCKED
e.Cancel = true;
}
}
}
Consider a form with a dataGridView bound to a strongly typed dataset. A combo box exists on the top to allow the user to select an employee. Once selected, the gataGridView's dataset is filled based on the employee's ID.
Some data entry is done on the dataGridView and once completed the user saves. In order to keep the user from accidently moving to another employee and deleting what they keyed, I prompt them to save is the dataset HasChanges() is true.
I was catching this piece of code in the SelectedIndexChanged event of the combo box but this also raises the event in the SelectedValueChanged
private void checkSaveChanges()
{
this.Validate();
this.laborTicketBindingSource.EndEdit();
if (dP_LaborTicket.HasChanges())
{
DialogResult result = MessageBox.Show("Do you want to save your changes?", "Save before closing?", MessageBoxButtons.YesNo, MessageBoxIcon.Question, MessageBoxDefaultButton.Button2);
if (result == DialogResult.Yes)
this.tableAdapterManager.UpdateAll(this.dP_LaborTicket);
}
}
Here is a snippet of the event that gets raised:
private void cmbEmployeeID_SelectedIndexChanged(object sender, EventArgs e)
{
checkSaveChanges();
if (cmbTransactionDate != null && cmbEmployeeID.SelectedValue != null)
{
string selectedDate = cmbTransactionDate.Value.ToString("MM/dd/yyyy");
string selectedEmployee = cmbEmployeeID.SelectedValue.ToString();
this.laborTicketTableAdapter.Fill(this.dP_LaborTicket.LaborTicket, selectedEmployee, selectedDate);
}
}
So stepping into this once I change a record and move to another employee, it steps into checkSaveChanges. Successfully validates and ends the edit and checks if it has changes (which it does).
After executing MessageBox.Show, the program is suddenly sent back to the cmbEmployeeID_SelectedIndexChanged event, where it calls checkSaveChanges yet again. This only happens twice though, and even if they say yes or no, the code within the prompting block runs.
How in the world is MessageBox.Show calling this twice? If I comment that line out this does not happen...
EDIT
As a bonus piece of information, the combo box AutoCompleteMode was set to SuggestAppend (Shows a dropdown as your typing) and DropDownStyle is set to DropDownList.
I changed the AutoCompleteMode to Append and this doesn't happen anymore, it seems to only happen with the SuggestAppend Mode...
I think Sven could be right that the MessageBox.Show will cause the dropdown to loose focus.
One way to work around this problem could be to detect if the event is already executing using a private boolean in the class. You'd then get something like this:
private bool fIsInEvent = false;
private void cmbEmployeeID_SelectedIndexChanged(object sender, EventArgs e)
{
if (!fIsInEvent)
{
fIsInEvent = true;
try
{
// your code
}
finally { fIsInEvent = false; }
}
}
I cannot close one of my forms programmatically. Can someone help me?
Here's the code:
private void WriteCheck_Load(object sender, EventArgs e) {
SelectBankAccountDialog sbad = new SelectBankAccountDialog();
DialogResult result = sbad.ShowDialog();
if (result == DialogResult.Cancel) {
this.Close();
} else {
MessageBox.Show(result.ToString());
}
MessageBox.Show(sbad.bankaccountID.ToString());
}
As configurator mentioned (in comments), the form must be shown before it can be closed, so, instead of the Load event, you should be doing this in the Shown event instead.
If you don't want the form visible for the Dialog box, I guess you can wrap the event code in a Visible = false;
In summary, the basic code would be
private void WriteCheck_Shown(object sender, EventArgs e)
{
Visible = false;
SelectBankAccountDialog sbad = new SelectBankAccountDialog();
DialogResult result = sbad.ShowDialog();
if (result == DialogResult.Cancel) {
this.Close();
} else {
MessageBox.Show(result.ToString());
}
MessageBox.Show(sbad.bankaccountID.ToString());
Visible = true;
}
By calling Form.Close(), the form should close, but not until all waiting events have been processed. You also still have a chance to cancel the form closing in the FormClosing event.
First, you'll probably want to return after your call to this.Close(). If it still doesn't close, step through your code and see what is happening. You may have to set and check a "forciblyClose" flag and return from any other processing methods before it'll actually close.
The actual problem is that windows won't let a form close on it's load method. I have to show the dialog on construction, and then if the dialog result is cancel I have to throw an exception and catch the exception on form creation.
This place talks more about it