如何在Winforms中创建一个“弹出”(提示,下拉,弹出)窗口?

时间:2011-12-29 14:57:21

标签: winforms winapi popup popupwindow

我如何制作,我会称之为" popup"窗口"在WinForms?


由于我使用了自己制作的单词" popup" ,让我举一个这个所谓的" popup"窗口:

  • 工具提示窗口(可以扩展到其父窗体的边界之外,不会出现在任务栏中,不是模态的,也不会隐藏焦点) :

    enter image description here

  • 一个弹出式菜单窗口(可以扩展到其父窗体的边界之外,不会出现在任务栏中,不是模态的,也不会偷取焦点):

    enter image description here

  • 下拉窗口(可以延伸到其父窗体的边界之外,不会出现在任务栏中,不是模态的,也不会偷取焦点):

    enter image description here

  • 主菜单窗口(可以扩展到其父窗体的边界之外,不会出现在任务栏中,不是模态的,也不会隐藏焦点):

    enter image description here

  • 更新 弹出窗口在使用鼠标或键盘进行交互时不会自行the "active" window("所有者"窗口仍然是活动窗口):

enter image description here

我在这个神秘的" popup"中寻找的属性就是这样:

  • 可以扩展超出其父表单的边界(即is not a child window
  • 没有出现在任务栏中(即窗口应该出现的窗口的启动式没有启动,也没有WS_EX_APPWINDOW扩展窗口样式)< / LI>
  • 不是模态(即doesn't disable its "owner"
  • 没有窃取焦点
  • 始终是 on-top 的所有者&#34; <34>
  • 不会成为&#34;活跃的&#34;窗口与[所有者保持活动时]进行交互

Windows应用程序已经在设法创建这样的窗口。我怎么能在WinForms应用程序中做到这一点?

相关问题

  • 如何在本机代码中实现上述所有功能?
  • 如何在Delphi中创建弹出窗口?
  • 我有这个本机代码来显示&#34; popup&#34; window - 在.NET中执行相同的操作需要什么P / Invokes?
  • 我在.NET中有一组P / Invoke - 我可以重用常规的WinForm,覆盖某些方法,以达到同样的效果吗?
  • 我有WinForm,我将其作为一个&#34; popup&#34;通过覆盖某些方法 - 是否有可以作为弹出窗口的内置Control
  • How to simulate a drop-down window in WinForms?

尝试#1

我尝试了Show(onwer) + ShowWithoutActivation方法:

PopupForm dd = new PopupForm ();
dd.Show(this);

使用PopupForm:

public class PopupForm: Form
{
    public PopupForm()
    {
        InitilizeComponent();
    }

    private void InitilizeComponent()
    {
        this.FormBorderStyle = System.Windows.Forms.FormBorderStyle.None;
        this.WindowState = FormWindowState.Normal;
        this.ShowInTaskbar = false;
    }

    protected override bool ShowWithoutActivation
    { get { return true; } }
}

几乎解决了这个问题,但随后我发现被提醒了另一个属性&#34; popup&#34; windows:他们没有从他们的&#34;所有者&#34;使用鼠标或键盘进行交互时,表单会变为活动状态。

3 个答案:

答案 0 :(得分:3)

您想拥有一个拥有的窗口。在您的主要表格中:

private void showPopup_Click(object sender, EventArgs e)
{
    PopupForm popupForm = new PopupForm();
    // Make "this" the owner of form2
    popupForm.Show(this);
}

PopupForm应如下所示:

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);
        }
    }
}

并确保PopupForm.ShowInTaskbar = false

答案 1 :(得分:3)

我很好奇组合框的下拉菜单和菜单是如何工作的,所以我做了更多的研究。

有两种基本方法。

将弹出窗口设置为由主窗口拥有的重叠窗口

如果弹出窗口具有嵌入式控件,或者您希望弹出窗口表现为无模式对话框,则需要此方法。

如果用户要在弹出窗口中与子控件进行交互,则必须接收激活。 (因此阻止激活的各种技术,例如处理WM_MOUSEACTIVATE是红色鲱鱼。)当它接收激活时,Windows将停用主窗口。解决此问题的方法是向父级发送WM_NCACTIVATE消息以更新其可视外观,而不更改其激活状态。这是.Net ToolStrip使用的方法,我的另一个答案用代码说明了它。

将弹出窗口设置为桌面窗口的子窗口

此方法由组合框下拉列表和(我猜)菜单使用,但您无法嵌入子控件,因此它不能广泛应用。

弹出窗口是子窗口,因此不会干扰激活。它总是在顶部。鼠标捕获用于检测弹出窗口外的点击并将其关闭。

但是,实施起来并不简单。激活仍然在主应用程序中,因此它保持焦点并接收击键。这似乎排除了弹出窗口中的嵌入式控件,因为它们无法获得焦点。组合框通过将击键消息转发到其下拉列表来处理此问题。 (请注意,菜单,组合框下拉列表等都是完全所有者绘制的,因为它们没有嵌入式窗口。)

答案 2 :(得分:0)

创建你的&#34; popup&#34;窗口作为桌面的子窗口,然后显示它而不激活它。

hWnd = CreateWindowEx(..., WS_CHILDWINDOW | WS_VISIBLE | WS_BORDER | WS_CLIPSIBLINGS, ..., GetDesktopWindow(), ...);
SetWindowPos(hWnd, HWND_TOPMOST, ..., SWP_NOACTIVATE);

执行此操作后,即使您单击&#34; popuped&#34;窗口。 &#34; popup&#34;窗口可以有自己的子控件。您可以单击它上面的按钮。但如果它是一个编辑控件,你就无法编辑它,我也不知道为什么。也许是因为原始窗口上已经有一个光标,闪烁。