Robert Rossney

I'm building a UserControl that, when clicked on, puts up a popup window. To make it behave properly (e.g. go away when the user clicks outside of the window or switches to another application), I'm using Steve McMahon's PopupWindowHelper class (see http://www.vbaccelerator.com/home/NET/Code/Controls/Popup_Windows/Popup_Windows/article.asp).

This class works by hooking a message filter into the owning form that watches for mouse-click events. When one occurs, the message filter checks to see if the mouse click is within the bounds of the popup form. If it's not, it raises the popup's cancel event.

This is good as far as it goes, but it considers any click outside the form to be a cancellation. This causes problems in the case where the popup creates a window that extends beyond its own bounds (like, for instance, the client area of a DateTimePicker, or a form displayed via ShowDialog).

I had thought to modify the filter class so that in addition to checking to see if the mouse click is within the bounds of the popup form, it also uses EnumChildWindows to traverse the descendant windows of the popup form, and see if the mouse click is within one of those.

And here's where I run into a brick wall. If I dump out the class of each window that the EnumChildWindows callback encounters at the time that I click on a date in the DateTimePicker, I get this:

WindowEnumProc: WindowsForms10.Window.8.app.0.3ee13a2

WindowEnumProc: WindowsForms10.STATIC.app.0.3ee13a2

WindowEnumProc: WindowsForms10.EDIT.app.0.3ee13a2

WindowEnumProc: WindowsForms10.STATIC.app.0.3ee13a2

WindowEnumProc: WindowsForms10.Window.8.app.0.3ee13a2

WindowEnumProc: WindowsForms10.BUTTON.app.0.3ee13a2

WindowEnumProc: WindowsForms10.EDIT.app.0.3ee13a2

WindowEnumProc: WindowsForms10.STATIC.app.0.3ee13a2

WindowEnumProc: WindowsForms10.SysDateTimePick32.app.0.3ee13a2

So EnumChildWindows has gotten to the DateTimePicker. But it never reaches the DateTimePicker's client area, which now extends beyond the bottom of the popup. (The rectangle returned by GetWindowRect for the last window listed above is entirely within the bounds of the popup.)

Similarly, if a control on the popup calls ShowDialog, EnumChildWindows never reaches the window of the form that's shown (and yes, I'm using the overload of ShowDialog that passes in the owner's handle), so any mouse click within the dialog that isn't also within the bounds of the popup causes the popup to close.

It seems to me that I must be misunderstanding something fundamental. Is there a straightforward way for me to determine if a mouse click occurs within a form, or any controls owned by that window



Re: Windows Forms General EnumChildWindows and modal dialogs

nobugz

Your problem is that you enumerating child windows. Popup windows, like a DTP calendar or a ComboBox list, are not child windows. They are toplevel windows, that's how they can show themselves on top of other controls and extend beyond the bounds of the form.

I don't really understand what problem you're trying to fix. What window or control could be clicked that should *not* close the popup





Re: Windows Forms General EnumChildWindows and modal dialogs

Robert Rossney

In between then and now I've figured that first part out. Good to know, but it doesn't solve my problem.

Okay, envision a form. Near the bottom edge of the form is a ComboBox. You click the arrow to drop down the list. A list appears, and the list is long enough that it extends beyond the bounds of the form. When you click on an item on that list, the form retains focus, even though you've clicked on something outside of its bounds.

That's what I'm trying to accomplish within my popup. I'm trying to build a UserControl that, when clicked on, drops down a form containing a bunch of controls. I want the form to remain where it is unless the user dismisses it, clicks outside of it, or switches to another application. It needs to remain visible even if some component on the form opens a modal dialog (otherwise I'd just handle its Deactivate event, which would otherwise work).

I've been seduced into the idea that I need to handle Windows messages in order to accomplish this. But maybe there's a better way that I'm not seeing.





Re: Windows Forms General EnumChildWindows and modal dialogs

nobugz

I'm having trouble with "remain visible even if ... opens a modal dialog". What would trigger the code that opens the dialog A mouse click





Re: Windows Forms General EnumChildWindows and modal dialogs

Robert Rossney

Sure. There's a control that may be in this popup (the exact contents of the popup are determined by context at runtime) that allows the user to select a code from a list. If the list is small, the control behaves like a dropdown ComboBox. If the list is large, it pops up a dialog with a searchable list of codes and descriptions.

I could just make this dropdown a modal dialog itself, and that's what I'm doing while I can't get it to behave properly. But there are several reasons in the broader information-management problem space that this UI is trying to address that it makes more sense to the users if this mode of editing doesn't (apparently) interrupt the flow of the application.





Re: Windows Forms General EnumChildWindows and modal dialogs

Aussie

I didn't even get that class to work :/

Form frm = new Form();
PopupWindowHelper pwHelper = new PopupWindowHelper();
frm.ControlBox = false;
frm.FormBorderStyle = FormBorderStyle.None;
frm.MinimizeBox = false;
frm.MaximizeBox = false;
frm.ShowInTaskbar = false;
frm.Text = "";
frm.TopMost = true;
pwHelper.ShowPopup(this,frm,new Point(250,250));

think I did exactly what that site said.. my main form keeps losing its focus Surprise