Reputation: 673
I have an interesting problem..
I have a Form that launches another Form (2) through a Button. Before Form2 Closes, it sometimes fires an Event which Invalidates Form 1 and forces Form 1 to refresh it's data. The problem I have is After Form 2 fires the event, Form 1 seems to get it and handles it, and refreshes it's data and Only then Form 2 Closes. I want Form 2 to Fire the event and Close, BEFORE Form1's event handler catches and processes the event.
I have a feeling it is related to BackgroundWorker
(sort of like SwingUtilities.InvokeLater in Java) .. but I am not that experienced with it ..
public class Frm1{
void LaunchForm2(){
Frm2 form2 = new Frm2();
form2.dataChanged += new DataChangeListener(myListener);
form2.showDialog();
}
private void myListener(){
//get my data again
}
}
public class Frm2{
private void Close(){
if(myDataHasChanged){
if(dataChanged != null) {
dataChanged();
}
this.Close();
}
}
}
Upvotes: 2
Views: 2461
Reputation: 64218
You can do this in OnHandleDestroyed as it it done after final destruction of the window handle. You can be certain that:
Thus do something like the following:
public class Frm2 : Form
{
protected override void OnHandleDestroyed(EventArgs e)
{
base.OnHandleDestroyed(e);
if (myDataHasChanged)
{
if (dataChanged != null)
dataChanged();
}
}
private void Close()
{
if (myDataHasChanged)
this.Close();
}
}
UPDATE:
Test to verify that HandleDisposed is called prior to returning from ShowDialog():
bool called = false;
Form test = new Form();
test.Shown += delegate (Object o, EventArgs e) { test.Close(); };
test.HandleDestroyed += delegate(Object o, EventArgs e) { called = true; };
test.ShowDialog();
Assert.IsTrue(called);
Upvotes: 2
Reputation: 887489
You can raise the event after calling Close
- calling Form.Close
will not exit the method that called it.
EDIT: Try using BeginInvoke
to wait for the next message loop before handling the event, like this:
form2.dataChanged += delegate { BeginInvoke(new DataChangeListener(myListener)); };
2nd EDIT: To give Form1 a chance to repaint, call BeginInvoke twice to wait two message loops before updating (One to close Form2, and a second to repaint Form1), like this:
form2.dataChanged += delegate(parameters) {
BeginInvoke(new Action(delegate {
BeginInvoke(new DataChangeListener(myListener), parameters);
}));
//Or,
BeginInvoke(new Func<Delegate, object[], IAsyncResult>(BeginInvoke),
new object[] { parameters }
);
};
Upvotes: 0
Reputation: 12401
Is there a specific reason why you're using events in this situation?
Expose a property on Form2 that allows you to check whether the data has changed. After the ShowDialog() call returns, check the value of the property and do your update if necessary.
(Edited to remove my now-useless code sample.)
Upvotes: 2
Reputation: 6932
Try changing the event call to:
public class Frm2{
private void Close(){
if(myDataHasChanged){
if(dataChanged != null) {
dataChanged.BeginInvoke();
}
this.Close();
}
}
}
This won't guarantee that the form closes before myListener() completes. However, it should allow the form to close without waiting for myListener() to complete.
Upvotes: -1
Reputation: 5320
Why don't you raise DataChanged Event in Closed event of form2?
Upvotes: 0