C # Winforms Threading - Delay Child form event until form closes

I have an interesting problem. I have a form that launches another form (2) via a button. Before Form2 closes, it sometimes fires an Event that cancels Form 1 and forces Form 1 to update the data. The problem is that after Form 2 fires the event, Form 1 seems to receive it and process and update its data, and only then does Form 2 Closes. I want form 2 to fire the event and close, BEFORE handling the event Form1 catches and processes the event. I have a feeling it has something to do with BackgroundWorker

(sort of like SwingUtilities.InvokeLater in Java) .. but I'm not that worried about 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();
    }
 }
}

      

+2


source to share


5 answers


You can raise the event after the call Close

- the call 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)); };

      



2 nd EDIT . To give Form1 the ability to redraw, call BeginInvoke twice to wait two message loops before updating (one to close Form2 and one to redraw Form1), for example:

form2.dataChanged += delegate(parameters) { 
    BeginInvoke(new Action(delegate { 
        BeginInvoke(new DataChangeListener(myListener), parameters);
    }));
    //Or,
    BeginInvoke(new Func<Delegate, object[], IAsyncResult>(BeginInvoke),
                new object[] { parameters }
    );
};

      

0


source


Is there a specific reason why you are using events in this situation?

Inject a property in Form2 that allows you to check if the data has changed. After the call to ShowDialog () returns, check the property value and update if necessary.



(Edited to remove my useless sample code.)

+2


source


You can do this in OnHandleDestroyed as you did after the window handle was finally destroyed. You can be sure that:

  • Will no longer be processed by Frm2
  • The call will always be fired when the form is closed

Thus, do 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 check that HandleDisposed is called before ShowDialog () returns:

        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);

      

+2


source


Why don't you raise the DataChanged event on the closed event of form2?

0


source


Try changing the event call:

public class Frm2{

 private void Close(){
    if(myDataHasChanged){
      if(dataChanged != null) { 
        dataChanged.BeginInvoke(); 
      }
      this.Close();
    }
 }
}

      

This does not guarantee that the form closes before myListener () completes. However, it should close the form without waiting for myListener () to complete.

-1


source







All Articles