views:

145

answers:

5

I have a very annoying problem and I'm trying to find the simplest solution possible, but I seem to keep complicating it.

My program displays a custom dialog box using the ShowDialog function (I create this form using a New constructor), but while my program waits for input in the dialogbox, my program continues to run other code, (I'm assuming initiated from other messages, but I still can't find good information on this, so as an aside to this topic does anyone have a reference about this), and arrives at this same point where the dialog box is to be displayed and displays it. So I end up getting a flood of dialog boxes.

My goal is prevent this excessive amount of dialog boxes. If the program arrives at this dialog initiation point I would like it to wait/pause until the first dialog box is finished.

I thought about threaded solutions, background workers, all kinds of ideas but they just seem to complicate things and I haven't actually fixed it.

Does anyone have an idea how I could prevent this from occurring?

Your help is greatly appreciate. Thanks

A: 

i would see 2 possibilities: if you have the dialog open in one position, than change there that it does not call the dialog box, but some sort of stack, and you can check when a dialog is closed, if there is stuff left on the stack.

or you change, when you opened the first dialog box, the owner window, that is passed to the dialog box, if possible. and hide that. if the owner is hidden -> the dialog box is hidden.

cRichter
+1  A: 

It seems to me that you have some very ugly bug in your code! I'd focus on fixing this bug first. The easy way to do this is to set a breakpoint on the line that opens up the dialog. When the line is hit the second time (while the first dialog box is still open), view the stacktrace at that point and check all active threads (View Threads and View Stack windows) for the cause of the issue.

In addition, change your code to open a modal dialog window instead, where the parent window must be the owner. A modal dialog window will stop execution and prevent the parent window from processing user input (which could've lead to this behavior).

Edit

From your comments I gather that you have several threads that you cannot control and that you want one thread at a time to access the messagebox code. When working with threads, there are several synchronisation primitives available. Expanding on each of them requires a book (you may try Concurrent Programming on Windows, one that's thorough while the book has some flaws in its structure), knowing the right one for you requires knowledge of your code.

That said, you may wish to do something like the following, using a Mutex which at least prevents other threads to access the code (meaning: it will put them in a suspend state until the Mutex is released). Add a static boolean flag variable (or add a checkbox on the popupped form "show box only once") if you want to prevent the popup box to show more than once. Mutex plus flag solves two problems in one: only one thread will ever run that code, and the code will only run once, ever.

// as static class variable, create a mutex
private static Mutex dialogMutex = new Mutex();

// a static flag preventing the dialog box to show more than once
// (you may wish to resolve this differently, depending on req's)
private static boolean dialogIsShownOnce = false;

public static void ShowDialogBox()
{
    // Wait until it is safe to enter, this makes the current thread 
    // the exclusive user of this code and other threads may only enter
    // after the current thread finishes.
    dialogMutex.WaitOne();

    // depending on your requirements, you may not want this
    // must come _after_ WaitOne to prevent entering before another
    // thread that entered hasn't yet changed this variable
    if(dialogIsShownOnce)
       return;


    // show your dialog box as a modal box 
    // if you are unsure: add a breakpoint just after the ShowDialog 
    // it should only be hit _after_ you dismiss the dialog box
    yourForm.ShowDialog();

    // set the flag, or the counter, or whatever you wish:
    dialogIsShownOnce = true;

    // Release the Mutex, this will remove the "roadblock" and allow
    // other threads to enter this piece of code
    dialogMutex.ReleaseMutex();
}

The code above is not tested and should be considered a hint on how to tackle this issue. There are so many ways to solve this, but I think the above method may just be what you need.

Abel
I've tried to debug already and indeed put the breakpoints as you've said and looked at the call stack on the second hit. I can trace it back to the point where it references "[External Code]" which is where another program is interacting with my program (I also think that GUI functions of my program create this situation too). So an external program and/or the GUI (to calculate and display a value) are causing my program to arrive a this point. I am calling the dialog box with ShowDialog() which I believe displays a Model form, and hence is currently restricting my input into the application.
clawson
@clawson: Forms are, by default, capable of handling things asynchronously. While user input is blocked, the parent form can still receive messages as may happen in the current case. If you want to block these message, use a static (!) true/false flag `BlockCommunication` which is used (read, not written!) by the methods that receive communication, or by the current method if communication should be received but should not trigger the window popup. Writing to this flag should be done thread-safe with, for instance, `lock` in the settor.
Abel
@Abel: This appears to be the case. Do you know where there is an example of this? (I couldn't find one.) Maybe if you write an example as an answer to this question I can accept it as the answer. I understand the theory behind the static flag, but I don't know what to do once I hit it. I don't want to return from the function, and if I sleep the thread won't that stop everything. I just want to pause execution along that 'message branch' (if that's what it's called), until the response is received. Thanks for your help.
clawson
@Abel: great, thanks for your answer, i think i will have to redesign my solution, because your solution is a multi threaded approach, but really my problem at the moment seems to be that the main application thread/gui thread is responding to multiple messages, and hence displaying multiple dialogboxes... this solution won't fix that, so if there is no way to prevent the main thread processing multiple messages i think I'll have to redesign it using multiple threads. unfortunately this is the only solution I can see.
clawson
@clawson: any form is multi-threaded by default. Many people don't know that, but it's a simple fact. They have to be to be able to receive messages even when the thread is suspended while waiting for user input (i.e., in your scenario with the Dialog). It's vital to find out what method is being accessed to process these messages. Basically, if you use the solution above (and follow the checks to insure multi-threadedness is the issue here, i.e., place that breakpoint) it should simply "just work". If not, then the bug must be something else, i.e., not to do with async messages.
Abel
PS: if you need an extra reassurance, you can send me a working example of your error and I'll have a look.
Abel
+1  A: 

I might be misunderstanding the issue here, but have you tried the following:

 Dim frmFindForm As dlgPromptForm

 frmFindForm = New dlgPromptForm()     

 If (frmFindForm.ShowDialog(Me) = DialogResult.OK) Then
    'Do something because they hit ok, if needed
 Else
    'Do something else because they didn't hit ok, if needed
 End If`

For this to work you will need to make sure your dialog form sets the DialogResult property when the user hits a button. (EX : On OK button click, DialogResult = System.Windows.Forms.DialogResult.OK)

This should cause your program to stop at the if, until the user pressed one of the buttons on the dialog.

Again this might be off from what you are looking for, but I really can't tell from the information you have provided.

Tony Abrams
A: 

Using ShowDialog() should never let the rest of the code to execute until the dialog is closed. So, my guess is that there is a problem with your code. As Abel recommended, you should use a breakpoint and trace your code. My other guess is that the other dialogboxes are being launched from within the original dialogbox, and it keeps happening recursively.

It would be easier to help if you post your code here.

Ansari
+1  A: 

I would simply create a form scope boolean say

DIM DisplayedMSGBOX as boolean = false

(If the threads are running on a separate form, simply make this boolean global)

public DisplayedMSGBOX as boolean = false )

and then at the point where the message box is displayed I would place

IF not DisplayedMSGBOX THEN

msgbox("This would be your msgbox")

ENDIF

AT some point if you want to reset the msgbox for use again simply

DisplayedMSGBOX = false

and now the msgbox is reset.

Michael Eakins