How can i make, what i will call, a \"popup\" window\" in WinForms?
Since i used my own made-up word \"popup\", let me give examples of this so-called \"p
You want an owned window. In your main form:
private void showPopup_Click(object sender, EventArgs e)
{
PopupForm popupForm = new PopupForm();
// Make "this" the owner of form2
popupForm.Show(this);
}
PopupForm should look like this:
public partial class PopupForm : Form
{
private bool _activating = false;
public PopupForm()
{
InitializeComponent();
}
// Ensure the popup isn't activated when it is first shown
protected override bool ShowWithoutActivation
{
get
{
return true;
}
}
private const int WM_NCACTIVATE = 0x86;
[DllImport("user32.dll", CharSet = CharSet.Auto)]
public static extern IntPtr SendMessage(IntPtr hWnd, int msg, IntPtr wParam, IntPtr lParam);
protected override void WndProc(ref Message m)
{
// The popup needs to be activated for the user to interact with it,
// but we want to keep the owner window's appearance the same.
if ((m.Msg == WM_NCACTIVATE) && !_activating && (m.WParam != IntPtr.Zero))
{
// The popup is being activated, ensure parent keeps activated appearance
_activating = true;
SendMessage(this.Owner.Handle, WM_NCACTIVATE, (IntPtr) 1, IntPtr.Zero);
_activating = false;
// Call base.WndProc here if you want the appearance of the popup to change
}
else
{
base.WndProc(ref m);
}
}
}
And make sure that PopupForm.ShowInTaskbar = false
.
Create your "popup" window as a child window of desktop, then show it without activating it.
hWnd = CreateWindowEx(..., WS_CHILDWINDOW | WS_VISIBLE | WS_BORDER | WS_CLIPSIBLINGS, ..., GetDesktopWindow(), ...);
SetWindowPos(hWnd, HWND_TOPMOST, ..., SWP_NOACTIVATE);
After doing this, your original window remains activated even if you click on the "popuped" window. The "popup" window can have its own children controls. You can click the button on it. But if it is an edit control, you cannot edit it, I don't know why. Maybe because there is already a cursor on your original window, blinking.
I was curious as to how combobox dropdowns and menus work, so I did some more research.
There are two basic approaches.
Create the popup as an overlapped window, owned by the main window
This method is required if the popup has embedded controls, or if you want the popup to behave as a modeless dialog.
If the user is going to interact with child controls in the popup window, it must receive activation. (So the various techniques for blocking activation, such as handling WM_MOUSEACTIVATE are red herrings.) And when it receives activation, Windows will deactivate the main window. The fix for this is to send a WM_NCACTIVATE message to the parent to update its visual appearance without changing its activation status. This is the approach used by the .Net ToolStrip, and my other answer illustrates it with code.
Create the popup as a child of the Desktop window
This method is used by combobox dropdowns and (I guess) menus, but you can't embed child controls so it's not widely applicable.
The popup is a child window so it doesn't interfere with activation. It is always on top. Mouse capture is used to detect clicks outside the popup and dismiss it.
However, this isn't straightforward to implement. Activation remains with the main application, so it keeps the focus and receives keystrokes. This seems to preclude embedded controls in the popup because they can't receive focus. The combobox handles this by forwarding keystroke messages to its dropdown list. (Note that menus, combobox dropdowns, etc. are all entirely owner-draw in the sense that they have no embedded windows.)