Menu

Modal Dialog Canceling FormClosing

Help
2012-02-16
2013-04-24
  • Sascha Lorbeer

    Sascha Lorbeer - 2012-02-16

    Hi there,

    I'm using the latest NUnitForms code from svn. I'm writing a test, who uses a Modal Dialog (displayed via Form.ShowDialog()) and it's driving me nuts. I try to explain (with a sample):

    By clicking the OK-Button in the Dialog, the DialogResult gets set to OK and the Dialog is about to get closed. Now there is an EventHandler registered on the FormClosing-Event, who's performing a validation on the input. If the validation fails, an error is set by an errorprovider and the FormClosing gets canceled. Watch the following snippet: The Validation is just about looking, if a TextBox is empty or not:

    private void TestForm_FormClosing(object sender, FormClosingEventArgs e)
        {
          ErrorProvider.Clear();

          if (this.DialogResult.Equals(DialogResult.OK))
          {
            if (string.IsNullOrEmpty(this.TextBox.Text))
            {
              ErrorProvider.SetError(this.TextBox, "I guess something is missing…");
              e.Cancel = true;
            }
          }
        }

    So i tried to write a test, that checks wether the error is set on the TextBox (after leaving the TextBox empty):

       
        public void ConfirmDialogWithoutInput()
        {
          TestForm testForm = new TestForm();

          ModalFormHandler = JustClickOk_ShouldNotCloseDialog;

          testForm.ShowDialog();
              
          Assert.IsTrue(testForm.Visible, "Form should not be visible!");
        }

        private void JustClickOk_ShouldNotCloseDialog(string name, System.IntPtr ptr, Form form)
        {
          ButtonTester ok = new ButtonTester("ButtonOk", form);

          ok.Click();

          // Now Check, if ErrorProvider is set on Control 'TextBox'!
          //
          TextBoxTester textBox = new TextBoxTester("TextBox", form);

          string foundError = ((TestForm)form).ErrorProvider.GetError((Control)textBox.TheObject);

          Debug.WriteLine("ErrorMessage is:" + foundError);

          Assert.IsNotNullOrEmpty(foundError, "ErrorProvider didn't set Error for TextBox, yet!");

          form.DialogResult = DialogResult.Cancel;

          form.Close();
        }

    By calling ShowDialog() the ModalFormHandler gets called and performs the specified actions. Now there is a problem, I can't solve:

    The FormClosing-Event is not getting fired (yet)…so the Validation is not getting performed! So these kind of Tests are getting pretty worthless.

    Am I missing something? Is this a (known) bug? Is there anyone, who experienced the same problem?

    Thanks!

    P.S.: Are there still active developers working on NUnitForms…is a new Release planned ? I know, there are several other (also opensource) GuiTesting-Tools, but we are using Infragistics Controls and NUnitForms is almost perfect for this purpose. So it would be very sad, if there are no future chances for improvements on this great framework :(

    Greetings from Germany,
    Sascha

     
  • Anders Lillrank

    Anders Lillrank - 2012-02-17

    Hi!

    You need to handle the DialogBox code in a delegate like this

    public void ConfirmDialogWithoutInput()
    {
    // TestForm should be the name of your modal dialog.
       ExpectModal("TextBox", delegate
      {
        TextBoxTester textBox = new TextBoxTester("TextBox", form);
          ButtonTester ok = new ButtonTester("ButtonOk", TextBox",);
          ok.Click();
         // Now Check, if ErrorProvider is set on Control 'TextBox'!
         //
        string foundError = ((TestForm)form).ErrorProvider.GetError((Control)textBox.TheObject);
        Debug.WriteLine("ErrorMessage is:" + foundError); Assert.IsNotNullOrEmpty(foundError, "ErrorProvider didn't set Error for TextBox, yet!");
         textBox .Close();
      });
        TestForm testForm = new TestForm();
        ModalFormHandler =  JustClickOk_ShouldNotCloseDialog;
        testForm.ShowDialog();
         testForm.DialogResult = DialogResult.Cancel;
         Assert.IsTrue(testForm.Visible, "Form should not be visible!");
    }

    Hope this helps

    best regards
    Anders Lillrank

     
  • Anders Lillrank

    Anders Lillrank - 2012-02-17

    Ignore TextBoxTester in last post, copy paste misstake.

    /Anders

     
  • Sascha Lorbeer

    Sascha Lorbeer - 2012-02-19

    Hi Anders, thanks for your quick reply.

    Unfortunately your suggestions didn't solve my problem. I used the (obsolete) ExpectModal-Method as you mentioned and received the same behaviour. So in my following explanations I'll keep refering to the (new) ModalFormHandler from the latest NUnitForms-Code (out of svn).

    So here is what I can report in detail:

    I'm setting the ModalFormHandler for the upcoming Modal Dialog. By invoking ShowDialog the Handler gets called. I can get all controls and use them. The Click-Event of the "OK"-Button is getting fired. (You should keep in mind, that there is no registered EventHandler for the Click-Event!) I set the DialogResult of the Ok-Button to DialogResult.Ok in Designer, thus the Dialog should get closed and the FormClosing-Event should get fired automaticly by setting the DialogResult of the Form. By Clicking the Ok-Button the DialogResult gets set, but the FormClosing-Event is not (yet) getting fired!

    So what happens next is that ModalFormHandler continues to work and tries to get Errors from the Forms Controls. That works fine, but there are no Errors set for any control, yet. Normally the test should fail at this point by using the assertion:

    string foundError = ((TestForm)form).ErrorProvider.GetError((Control)textBox.TheObject);
    Assert.IsNotNullOrEmpty(foundError, "ErrorProvider didn't set Error for TextBox, yet!");

    But thats also not happening. I'm not quite sure if an AssertionException is getting thrown or the test just hangs on that line. (I'm using NUnit-TestRunner and VisualStudio 2010 Express…so its a bit hard to investigate :(  …maybe I find time to debug the test a little bit while I'm at work)

    Finally after all actions/assertions are made the FormClosing-Event gets fired and the errorprovider sets errors on the specified controls. So I think it could be kind of a threading-problem…but i don't know either if it's caused by NUnitForms or NUnit in general. What's your opinion on that? Do you have any ideas how i can get rid of it?

    Sascha

     
  • Sascha Lorbeer

    Sascha Lorbeer - 2012-02-20

    I think i found the actual problem (and a solution :-) ) … the events (FormClosing, FormShown, …) are getting fired much too late. So the most senseful and simplest solution is: Waiting until the needed Events occur!

    To simplify, a test that requires working off certain events, could look like this:

    public void AnyTest()
    {
        …

        this.ModalFormHandler = SomeHandler;

        Form.ShowDialog();

        …
    }

    public void SomeHandler(string name, IntPtr ptr, Form form)
    {
        form.AnyEvent += delegate {… do some actions …};

        form.AnotherEvent += delegate{… do some assertions …};
    }

    In my case, i subscribed to FormShown and FormClosing-Event. The delegate for FormShown-Event was performing my button.Click, so that any time later the FormClosing-Event gets fired and does the validation.

    I still don't know who is blocking the events to get fired, but it seems so that leaving the ModalFormHandler is pretty important for firing the events at all. Although the order of the events is not always as expected…i.e. i got in situations where formShown-Event occured AFTER FormClosing-Event. Therefore it was also necessary to perform my click-actions not before FormShown-Event occured. I'm still thinking that this is a bug, but i don't know how to fix nor where to find it. Does anybody else have an opinion on this?

    Greetings
    Sascha

    P.S.: without these two links, i propaply wouldn't have been able to find this solution:

    http://www.peterprovost.org/blog/post/Unit-Testing-Events-with-Anonymous-Delegates-in-NET-20.aspx

    http://www.marcusoft.net/2006/10/nunit-testing-asynchronous-events.html

     
  • lhab

    lhab - 2012-02-24

    Here is the explanation:
    - ShowDialog shows the form and runs its own message loop
    - the ModalFormHandler is run from inside this loop
    - the form.DialogResult property is a trivial wrapper around a field in the form object, assigning to it does not trigger anything
    - the message loop in ShowDialog periodically checks wether the DialogResult property has been set by a message handler, in which case it attempts to close the form, and will run the form closing event.

    Therefore, the FormClosing event cannot be run inside the ModalFormHandler. So, what I would do, is put the code following ok.Click()  inside a BeginInvoke, so that is run later on by the message loop.

     
  • lhab

    lhab - 2012-02-25

    Regarding your question about active developers, well, Andreas regularly updates the included nunit binaries, but no one seems to have time to do any further work.

    Personally, I had joined the project two years ago, in order to contribute some fixes that I made after using nunitforms at work. As I only use the dialog management framework (our interfaces are too nested and dynamic to be able to identify controls by ther names), I have little motivation to  work on the rest.

    One nice thing to have would be a working sendkey system, seeing as the two that we have are unreliable. When I need to simulate keyboard input, I just perform a SendMessage by hand, but that does not always work (but deterministically so, at least).

    Same thing with mouse simulations.

     

Log in to post a comment.