Go Premium for a chance to win a PS4. Enter to Win

x
  • Status: Solved
  • Priority: Medium
  • Security: Public
  • Views: 3779
  • Last Modified:

How to close a Modal Dialog form from parent form

I have a form, that intercepts keyboard input (using Application.AddMessageFilter) to determine input from a barcode scanner (this is not important for the purpose of this question).

When a serial number is succesfully validated from this filter, a process is spawned (syncronously I assume) to search a DB for this serial number. If it is not found, a modal dialog is shown to determine what to do with it.

If I then scan another barcode, I want the modal form to be closed, and forgotten about, so that the process can start again (and show the modal form again if necessary). If the modal form is not needed, there is no problem (the modal form will show again the next time its needed without any issues), if however the modal form is needed again as part of the same process that closed the previous instance, then I receive this error:

InvalidOperationException was unhandled.

"Form that is already displayed modally cannot be displayed as a modal dialog box. Close the form before calling showDialog."

Some code:
        frmUnknownItem dlgUnknownItem = new frmUnknownItem();

        public frmMain() {
            InitializeComponent();
            Application.AddMessageFilter(new KeyboardMessageFilter(this));
        }

// This is called when a valid serial number is detected from the barcode scanner via the KeyboardMessageFilter
        private void ProcessInputtedText(string InputtedText) {
            dlgUnknownItem.CloseIfOpen();

            if ("FOUND IN DB") {
                //Do as required
            } else {
                //Otherise, open modal dialog form.
                dlgUnknownItem.SetOptions(InputtedText);
                dlgUnknownItem.ShowDialog();
                //More code depending on decision from the modal dialog
            }
        }


class frmUnknownItem : Form {
        bool _isOpen = false; //flag is set to true when form is shown.

        public void CloseIfOpen(){
            if (_isOpen) {
                _isOpen = false;
                this.Hide();
                this.Close();
            }
        }
}

Open in new window


Maybe this is just a huge logic flaw, as the code is siting and waiting for the modal form to close so it can continue execution through the method, but at the same time the keyboardmessagefilter spawns a new process that closes the form from a different instance of the method that opened it... so there could be two instances of code running at the same time? is that correct? I am not presented with any of the usual multi-threading issues that I would normally face if this is true.

Any thoughts, ideas, suggestions, or teachings please?

The form has to be modal, and it has to be programatically closable and forgotten about...
0
DjDezmond
Asked:
DjDezmond
  • 7
  • 6
  • 3
  • +2
1 Solution
 
Gururaj BadamCommented:
I'm expecting that when you say closeable you meant to close/dispose not hide? Is this dialog custom dialog or standard messagebox?
0
 
DjDezmondAuthor Commented:
it is a normal windows form, and when I say closeable, i mean hideable really, as I want to reuse the one instance of it on my main form.

The error suggests it needs to be closed though? and calling just Hide() makes no difference at all.

I suspect this is more of a wierd threading issue, as the code works fine as long as the modal form is not re-opened in the same pass that closes it (if that makes sense :-/ )
0
 
Naman GoelCommented:
can you send me complete code and exception call stack on my email address

goel.naman@gmail.com
0
Independent Software Vendors: We Want Your Opinion

We value your feedback.

Take our survey and automatically be enter to win anyone of the following:
Yeti Cooler, Amazon eGift Card, and Movie eGift Card!

 
Gururaj BadamCommented:
Post your code here for reference rather sending out in email.
0
 
Todd GerbertIT ConsultantCommented:
I'm not sure this is necessarily the best approach, but the first thing that comes to mind...since using ShowDialog(), by definition, halts execution in the calling thread I think you're going to run into issues.  Instead, try setting the "Owner" property of your modal dialog to be your main form - and on open of the modal dialog disable the parent form and on close of the modal enable it.
In your message filter you can simple check to see if the modal has been disposed/is visible and close it if yes.
0
 
Todd GerbertIT ConsultantCommented:
Sorry, got distracted by a phone call...forgot to attach this code.
using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Data;
using System.Drawing;
using System.Linq;
using System.Text;
using System.Windows.Forms;

namespace WindowsFormsApplication1
{
	public partial class Form1 : Form, IMessageFilter
	{
		private const int WM_LBUTTONDBLCLK = 0x0203;
		MyModalDialog modal;

		public Form1()
		{
			InitializeComponent();
			Application.AddMessageFilter(this);
		}

		public bool PreFilterMessage(ref Message m)
		{

			if (m.Msg == WM_LBUTTONDBLCLK)
			{
				if (modal != null && !modal.IsDisposed)
					modal.Close();
				modal = new MyModalDialog(this);
				modal.Show();
				return true;
			}
			else
				return false;

		}
	}

	public class MyModalDialog : Form
	{
		public MyModalDialog()
		{
			this.Load += new EventHandler(MyModalDialog_Load);
			this.FormClosing += new FormClosingEventHandler(MyModalDialog_FormClosing);
		}

		void MyModalDialog_FormClosing(object sender, FormClosingEventArgs e)
		{
			if (this.Owner != null)
				this.Owner.Enabled = true;
		}

		void MyModalDialog_Load(object sender, EventArgs e)
		{
			if (this.Owner != null)
				this.Owner.Enabled = false;
		}
		public MyModalDialog(Form owner)
			:this()
		{
			this.Owner = owner;
		}
	}
}

Open in new window

0
 
DjDezmondAuthor Commented:
The project itself is part of a "suite" of tools I am developing, and too big and unneccessary to upload. I have taken the three forms relevant to this issue.

All of the database code is stored in a DLL file, and as the databases themselves are held internally within our company, you wouldn't be able to access them anyway, so you will just have to use your intiative and replace any invalid references with True or False statements to mimic the desired outcome.
StockIO.zip
0
 
DjDezmondAuthor Commented:
tgerbert:

Thanks for your suggestion, I tried to implement that, to no avail.

public MyModalDialog(Form owner)
:this()
{
this.Owner = owner;
}

:this() returned an error saying that it didn't except 0 paramaters?
If I removed that, the error still showed as before.
0
 
Todd GerbertIT ConsultantCommented:
My example modal dialog form has two constructors, one taking zero parameters and one taking a single Form parameter.  The this:() line associated with the 1-parameter constructor causes the parameter-less constructor to be called first, before the 1-parameter constructor.  This allows you to put code that is common to both constructors in one place (the parameter-less constructor), and code specific to the 1-parameter constructor in that constructor.
public class MyModalDialog : Form
{
    public MyModalDialog()
    {
        this.Load += new EventHandler(MyModalDialog_Load);
    }
    public MyModalDialog(Form owner)
      :this()
    {
        this.Owner = owner;
    }
    private void MyModalDialog_Load(object sender, EventArgs e)
    {
        // blah blah blah
    }
}

Open in new window

0
 
DjDezmondAuthor Commented:
Actually I am lying, i forgot to reinitialize the form before opening again.

So that works now, kind of, but I can re-mould it back into how I want it displaying. So thanks for that.

I think more so, I was kinda wanting an explanation about the execution contex around this, as it wasn't making sense to me. Obviously ShowDialog() halts execution as you said, so how could the KeyboardMessageFilter carry on executing, without being multithreaded? I was able to close the modal dialog box ok from outside of the calling thread, without invoking or messing about jumping between threads.

Its kind of multithreading without being multithreaded...? is that right?
0
 
Todd GerbertIT ConsultantCommented:
...therefore you must be missing the parameter-less constructor is the point I was trying to make. ;)
0
 
DjDezmondAuthor Commented:
tgerbert::

yes mate, i realised that afterwards, i was just being a tard and not reading your code fully!
0
 
Gururaj BadamCommented:
I don't see any issues with your code. I'm attaching the working code for your reference.
StockIO.zip
0
 
Todd GerbertIT ConsultantCommented:
Well, I'm a little foggy on the details of that myself - but I suspect that the reason the MessageFilter still works is either because the ModalDialog's WndProc is processing messages, or because the behind-the-scenes code of ShowDialog is actually a loop that continually alternates between processing Windows messages and running the code for the modal window.
I wonder if the message filter continues to work if you show a message box, or System.Threading.Thread.Sleep() in the modal window?
0
 
DjDezmondAuthor Commented:
OK thanks Novice Novice,

Although you have removed most of it, well the relevant bits anyway, so maybe I should have thought more about what I was (or wasn't) posting on here, as you were obviously unable to create a working example with the amount of missing references. so sorry about that.
0
 
DjDezmondAuthor Commented:
hmm, yea maybe worth a look tomorrow when I get back into the office. I am the kinda person who needs to understand everything about why something works the way it does before I can properly utilize it to its best potential elsewhere.

Cheers again anyway tgerbert.
0
 
Todd GerbertIT ConsultantCommented:
fyi...Quick test tells me that the message filter stops working as soon as the thread is Sleep()'ed or MessageBox.Show(...), so I'd venture to say so long as any form is open and processing Windows messages in the queue the message filter will continue to work.
0
 
MathiyazhaganCommented:
create frmUnknownItem   object  in local scope and dispose it after it serves it's purpose. as

 using( frmUnknownItem  dlgUnknownItem= new frmUnknownItem  ())
{
   //code here
 
}
"using " keyword dispose object when scope completed.set DialogResult value in frmUnknownItem  to close it  like

private     bthOK_click(object sender,EventArgs e)
{
     this.Count =localvalue; //somethimk like that
      DialogResult = DialogResult.OK; //closes the modal dialog
}
private     bthCancel_click(object sender,EventArgs e)
{
         DialogResult = DialogResult.Cancel; //closes the modal dialog
}


depending DialogResult  value of frmUnknownItem  :

                   if (dlgUnknownItem.ShowDialog() == DialogResult.OK)
                  {
                     //More code depending on decision from the modal dialog
                      int intValue = dlgUnknownItem.Count;//something like
                  }

hope this helps. if you want to run in single thread at time use lock () as:

            if ("FOUND IN DB") {
                //Do as required
            } else
              {
                     object sync = new Obejct();
                      lock(sync)
                       {
                           //show frmUnknownItem
                       }    
                }
 
private void ProcessInputtedText(string InputtedText)
 {

            if ("FOUND IN DB") {
               
            } 
           else {
                //Otherise, open modal dialog form.
                using( frmUnknownItem  dlgUnknownItem= new frmUnknownItem  ())
                {
                   dlgUnknownItem.SetOptions(InputtedText);
                   if (dlgUnknownItem.ShowDialog() == DialogResult.OK)
                  {
                     //More code depending on decision from the modal dialog
                      int intValue = dlgUnknownItem.Count;//something like
                  }
                }
            }
        }

Open in new window

0

Featured Post

What does it mean to be "Always On"?

Is your cloud always on? With an Always On cloud you won't have to worry about downtime for maintenance or software application code updates, ensuring that your bottom line isn't affected.

  • 7
  • 6
  • 3
  • +2
Tackle projects and never again get stuck behind a technical roadblock.
Join Now