Fog Creek Software
Discussion Board




As cunning as a.... modal form

Until yesterday I had never appreciated how cunning modal forms must be. And of course this really came to light because I want to reproduce the functionality and I cannot do it!

I'm using .NET and the application is encapsulated within an MDI form. I like MDI forms; all of the windows related to your application neatly containered with window management built in.

However, for some reason you cannot use modal dialogs (In .NET by using the .ShowDialog() method) in an MDI container but I really need/want to.

I've tried (unsuccessfully) to simulate it in a couple of ways but I cannot work out, in the real implementation, what it's doing.

It seems to have the effect that your code stops, mid-function,  where the modal dialog is called and when the dialog completes execution contines where it left off..

e.g.
..set up some local variables..
..do some work..
ShowDialog()    ' we now wait here
..do some more work..
..local variables still available..

Now I cannot reproduce this. There is no way of halting the method mid-sentence without blocking the main thread which of course stops all the windows messages from being actioned.

I've tried different scenarios using multiple threads and I actually got something that sort of worked but was very inelegant and not suitable for using as a generic solution.

Therefore I've come to the conclusion that this must be a very underrated bit of code!

Does anyone know how it works and how one could simulate the functionality?

Thanks in advance (my head hurts)

gwyn
Wednesday, December 10, 2003

It disables the window with respect to which your dialog will be modal and then it runs the message loop until the modal dialog is closed.

K
Wednesday, December 10, 2003

I don't work in the .NET world, but I've simulated this behavior in other environments as:

[Warning: bad pseudocode follows ..]

SomeFunctionThatUsesTheDialog()

  // do some stuff

  Call DisplayMyModalDialog

  // do some other stuff

End function

DisplayMyModalDialog()

    Dialog.Show // or whatever

    Do Until (Dialog.IsNotOpen)
          DoEvents // process any other external events
    Loop

End function

Unfortunately, this method burns CPU cycles while it waits for the dialog to close, and uses the often dreaded DoEvents, but it works for me.

Sgt. Sausage
Wednesday, December 10, 2003

==> Shitty code by shitty coders.

My thoughts exactly. My submitted pseudocode is, admittedly, in this category, as well as my coding skills. I spend most of my time slogging batch based T-SQL, and front-end GUI is not a place I work in. I'll admit it. Shitty code from a shitty GUI developer.

Given that, I've used the (pseudo)code I submitted and it does work.

Your point is <???>

Sgt. Sausage
Wednesday, December 10, 2003

K - yes I understand what it functionally does... what I don't undestand is HOW it achieves that!

Sgt. Sausage - Thanks for this idea... (I had forgoetten DoEvents - don't write front end stuff very often!)... however the 100% CPU burn will look a bit naff. For example whenever you open Access it starts burning 100% for some reason.... (and I always think 'Microsoft you assholes!') Mind you perhaps they've set a precendence over the acceptibility of this...

gwyn
Wednesday, December 10, 2003

gwyn, if you have access to the OS primitives (or some equivalent in your framework) then my description is essentially the same thing that you'll do.  For Windows, it'd look like:

EnableWindow(hParent, FALSE);
hModalChild = CreateWindow(...);

MSG aMsg;
while (valid_gm_result(GetMessage(&aMsg, NULL...)))
{
  ProcessMessage(&aMsg);
  if (WindowClosed(hModalChild)) break;
}

EnableWindow(hParent, TRUE);

On the Mac you can use the 'run loop' functions to get the same effect.  The crux of it is in 'GetMessage' (or whatever OS message functions are available), since it will place your process in a wait state until a message is available (avoiding the 100% CPU time problem using a method that just polls the message queue, eg: DoEvents in VB).

There are a lot of other boring implementation details hidden behind your framework.

K
Wednesday, December 10, 2003

K - what I still can't do is pause my code in the middle of a function.... I can already get notified of events when a window closes but that will fire a separate method and not continue where we left off..

I want to be able to:

Function X()

..do some stuff..
Show Modal Form
Wait until it is closed
..do more stuff

End Function

But I don't know how to implement the 'wait' bit. Really I want to tell the thread it 'your work is finished here for now' but 'come back later and carry on where you left off'.

gwyn
Wednesday, December 10, 2003

I apologise for the contrarian nature of this post, but... have you considered the alternative, namely to fake the MDI stuff instead? It's easier than you might think.

For example, in .Net, a form is a control, so you can display a form on a tab page simply by setting TabPage.Control = myForm.

Just a suggestion...

Dave Hallett
Wednesday, December 10, 2003

There are lots of archived newsgroup posts on this topic.  (Although not a clear solution.)  Perhaps they can help...

http://groups.google.com/groups?hl=en&lr=&ie=UTF-8&oe=UTF-8&q=modal+mdi&meta=group%3Dmicrosoft.public.dotnet.*

Robert Jacobson
Wednesday, December 10, 2003

gwyn, I don't understand -- what I described would allow you to do that.  Put it in a function called ''ShowMyModalFormAndDontReturnUntilItsClosed()" and you can use that function just like you describe.

K
Wednesday, December 10, 2003

OK I've reread and I think I understand.

We're intercepting all messages, passing them on and then when we see the one we want we're continuing.

Don't know how in .Net you get to intercept the system messages... if you can...

I've got an article on it somewhere so I'll look it out.

tx

gwyn
Wednesday, December 10, 2003

This article might help:

http://msdn.microsoft.com/library/default.asp?url=/library/en-us/dnadvnet/html/vbnet07092002.asp

Robert Jacobson
Wednesday, December 10, 2003

We're creating a MDI container in C#.  For the child windows, we call .Show() instead of .ShowDialog() so that the dialog works modelessly rather than as a modal.

Walt
Thursday, December 11, 2003

There's a very simple answer to you question, you are making far, far too much hard work for a simple requirement.
I'm not trying to be a smart ass - but I suspect if you read the introductory chapter on form management for .NET the anser will be a simple switch or something.

You jumped straight to Ch 10, didn't you?
Friday, December 12, 2003

*  Recent Topics

*  Fog Creek Home