3

Should sound weird, but this is just for my hobby. I would want a (custom) messagebox to pop up with a YesNo buttons which should ideally block the code. But I should be able to click on the parent form so that I can dismiss the message box without having to specifically click on the messagebox buttons (equivalent to clicking No on the message box)..

something like this:

     void Foo()
     {
         CustomMsgBox.Show("do you really wanna delete?", CustomMsgBox.Buttons.YesNo);
         //block the code here, but user should be able to click on form, so that its equivalent to have clicked No;
         //if clicked No, return;

         //delete.
     }

So the solution I thought was make the custom message box non modal - so that user can click on form, but I'm not able to block code.. How can i do that?

It would look like this:

 void Foo()
 {
     NonModalMsgBox.Show("do you really wanna delete?", CustomMsgBox.Buttons.YesNo);
     //block thread till user clicks on form or messagebox buttons.
     //unblock when user clicks.
     //if No, return;

     //delete.
 }

Edit: I know this is not a standard practice and I know non modal forms do not block, while modal forms do. So please do not recommend to be content with either modal form's or non-modal form's behavior. My question would be is there any way to simulate the behaviour of ContextMenu with windows forms.

nawfal
  • 70,104
  • 56
  • 326
  • 368
  • This isn't possible because it would be re-entrant, which would be likely to mess you up. – SLaks Dec 19 '11 at 21:10
  • I dont believe this is impossible ultimately. I can block the thread indefinitely, but it freezes the main form too.. that's my worry. I hope more knowledgeable ppl can provide a work around.. I'm just toying with various aspects of .net basically.. should be nice to know how can this be achieved – nawfal Dec 19 '11 at 21:13
  • 1
    This requires a loop that calls Application.DoEvents(). With the hazards attached to that method. See http://stackoverflow.com/questions/5181777/use-of-application-doevents/5183623#5183623 – Hans Passant Dec 19 '11 at 21:18

6 Answers6

4

You can solve this quite easily. Create and use a modal dialog but override the WndProc of the dialog and process the WM_MOUSEDOWN event. Check the position of the mouse down and if it is over the parent window but not over the dialog itself then simply dismiss the dialog.

Phil Wright
  • 22,580
  • 14
  • 83
  • 137
  • can you provide the basic code, or a link to some sample code? i'm a novice in these things.. – nawfal Dec 19 '11 at 21:31
2

Essentially you can't do this in a 'blocking' call easily. What you could do easily enough is to either pass the information required to perform the delete, or a delegate to perform the operation, to the form. When they click Ok you simply perform the operation. If they activate the parent form, then just close the child.

csharptest.net
  • 62,602
  • 11
  • 71
  • 89
  • sorry, I did not understand what you meant. Can you show me little piece of code. I'm a bit weak with delegates.. – nawfal Dec 19 '11 at 21:20
1

Another way of handling this is by manually enabling the parent form when calling ShowDialog, from here

[DllImport("user32.dll")]
private static extern bool EnableWindow(IntPtr hWnd, bool enable);

internal static DialogResult ShowDialogSpecial(this Form formToBeShown, Form parent)
{
    parent.BeginInvoke(new Action(() => EnableWindow(parent.Handle, true)));
    formToBeShown.ShowDialog(parent);

    return formToBeShown.DialogResult;
}

Just call the extension method from any parent form like this:

var f = new Form();
f.ShowDialogSpecial(this);
//blocks but parent window will be active.

Of course you need to handle the clicks on parent form to close child form.

Community
  • 1
  • 1
nawfal
  • 70,104
  • 56
  • 326
  • 368
1

You want the user to be able to click the background window to cancel the dialog box? Add a handler to the background window so that when the user clicks on it you check to see if the non-modal window is displayed, if so close it.

Sounds easy, but you will need to be careful to handle every possible click on the background window and child windows. That sounds like a can of worms I wouldn't want to go down.

Perhaps instead you could detect if the non-modal dialog box loses focus and automatically close it. I can see this behavior making sense for a simple "confirm delete" dialog box, but as a user my first reaction is going to be to spam the ESC key to close the dialog box.

Brian Ensink
  • 11,092
  • 3
  • 50
  • 63
  • I can do all this brian, but the worry here is, a non modal form is not blocking, and hence it doesnt block the code in YesNo situations. This is not what I'm basically looking for. – nawfal Dec 19 '11 at 21:35
  • The main feature of a modal dialog is that it is blocking. The main feature of the non-modal dialog is that it is non-blocking. You want blocking non-modal dialog box which seems like a contradiction of sorts. Popup menus automatically close when they lose focus and that seems very close to what you describe. – Brian Ensink Dec 20 '11 at 14:45
  • Can you tell me what .net gui component is a popup control? Also is it blocking? – nawfal Dec 20 '11 at 18:31
  • You could use the [ContextMenu.Show method](http://msdn.microsoft.com/en-us/library/s00cc2f3.aspx) if a simple menu is enough. Otherwise make a new dialog box and detect when the focus leaves the dialog box. – Brian Ensink Dec 20 '11 at 18:43
  • this seems cool. actually this is what you mentioned in your post as answer but with the difference here you mention a modal dialog, while in your answer you mentioned non modal dialog. you may edit your question to make more sense.. – nawfal Dec 20 '11 at 18:47
  • you can't actually close a modal dialog based on user events on parent form, like validating,mouse down, lost focus, leave etc since those events dont fire up as long as modal form blocks all that. Context menus are a nice way out, but looks too different from a normal message box.. – nawfal Dec 21 '11 at 05:57
  • @nawfal, Use a non-modal dialog box and detect the loss of focus. – Brian Ensink Dec 21 '11 at 16:52
  • non modal dialog doesnt block, and thats why I came here. I got a solution Joe White. I know how to get the child form closed on user click, focus loss etc.. – nawfal Dec 21 '11 at 17:19
  • @nawfal, Again, what you want doesn't exist in the exact form you want it. You want a blocking call on the main thread but still you insist that the main thread be able to handle an event like "click". You cannot have it both ways. I suggest using a popup menu or a non-modal dialog box and handling the focus event. With that you could let the user click on the main form and automatically close the dialog box. – Brian Ensink Dec 21 '11 at 19:13
  • I know how to close a non modal form anyways, my question here was not that. I do not understand why do you keep repeating about non modal form when it doesnt block. //You want a blocking call on the main thread but still you insist that the main thread be able to handle an event like "click".// This does not hold water, your later suggestion with popup menu does exactly what I'm looking for. How did .net achieve it? I was looking a way out to simulate that behaviour with a form control. – nawfal Dec 21 '11 at 19:23
  • I thought of asking about it in a community with more knowledgable ppl. I detailed the requirement in my question. I do not want to block the main thread per se, what I wanted was to block the function keeping the event handlers ready to respond. In a way, as pointed out by Joe White on context menus. Non modal forms no way does that unless by the method pointed out by Joe White again. Please do not recommend using non modal forms the way you do another time. – nawfal Dec 21 '11 at 19:33
  • @nawfal, Ok, sorry I couldn't be more helpful. I guess I don't understand exactly what you want. I tried to explain a way to make a dialog box behave like the popup menu. I don't know your background on Windows programming, but you might enjoy learning more about the Win32 message loop. It might help you better understand how some of these things work and the message loop is still very much a part of WinForms. (I apologize if you already know all about this!) Good luck to you! – Brian Ensink Dec 22 '11 at 16:18
  • haha thanks mate.. Yes you tried, but what rather annoyed me was that you are not understanding my requirement despite making it clear. Each time you say to have non-modal form, but that doesnt block. Closing the form with a click isn't my problem, but blocking the thread till I click :) Cheers :) – nawfal Dec 22 '11 at 18:19
0

An easier way: set form's "TopMost" property to be True. Then it will act like blocking

dong
  • 1
0

You could do something like:

public void ShowMe() {
    Show();
    while (!_receivedDeactivateEvent)
        Application.DoEvents();
}

I'm not sure I'd recommend it, though -- I'm not sure how stable it would be, nor am I sure whether it would behave the way you want if you click the Delete button on the parent form while the 'dialog' is up (would it close the first dialog first, or leave it up? might be the latter, which could get messy).

Joe White
  • 94,807
  • 60
  • 220
  • 330
  • Ppl say this is a bad method, but as long as I get this to be working according to my need and I cant understand others' methods without code, I'll mark this as the answer. I can handle rest of the conditions u were talking about.. Thanks :) – nawfal Dec 19 '11 at 22:11
  • @nawfal It is the answer to your question, but it's a *very bad thing to do*. I almost guarantee you will have problems with your program that you will pull out lots of hair trying to figure out... – Andrew Barber Dec 19 '11 at 23:31
  • @Andrew Barber I would of course not toy with .net fundamentals in my apps I will ship or deploy elsewhere. This is just a simple hobby program with which mainly I try to learn .net gui component behaviour etc.. doesnt matter. moreover I'd taken care of situations the answerer was talking about already – nawfal Dec 19 '11 at 23:35
  • 2
    @AndrewBarber, this *can* be made to work -- it's basically how PopupMenu works. But yes, it's very error-prone and takes a lot of work to get it right. – Joe White Dec 19 '11 at 23:39
  • @JoeWhite, No I don't think that is how popups work. Popups automatically close when they lose focus. The popup is entirely self contained and doesn't require external code to tell it when to close. The while() loop in this answer requires external code to tell it when to close which sounds very hard to get right and maintain with many special cases. – Brian Ensink Dec 20 '11 at 14:38
  • 1
    @BrianEnsink, I'm not talking about WPF's [Popup](http://msdn.microsoft.com/en-us/library/system.windows.controls.primitives.popup.aspx), I'm talking about popup menus (aka context menus). The Win32 [TrackPopupMenu](http://msdn.microsoft.com/en-us/library/windows/desktop/ms648002%28v=vs.85%29.aspx) function shows a popup menu and doesn't return until that menu is closed. WinForms' [ContextMenu.Show](http://msdn.microsoft.com/en-us/library/s00cc2f3.aspx) has the same behavior: it doesn't return until the popup menu is closed. – Joe White Dec 20 '11 at 15:24
  • @JoeWhite, Those are good examples but none of them require an external poke from user code to close them. The popups will use their own message dispatch loop (which is how they can be blocking function calls) but they don't require error-prone external code to tell them when to close. The more I think about this, the OP needs to use a popup menu of some kind. It seems to be exactly what he wants. – Brian Ensink Dec 20 '11 at 16:17