如何使窗口始终保持在.Net的顶部?

时间:2009-03-25 20:33:06

标签: c# .net winforms

我有一个C#winforms应用程序在另一个程序中运行宏。另一个程序将不断弹出窗口,并且通常会让事情看起来,因为缺少一个更好的词,很疯狂。我想实现一个取消按钮来阻止进程运行,但我似乎无法让窗口保持在最顶层。我如何在C#中执行此操作?

编辑:我试过TopMost = true; ,但另一个程序不断在顶部弹出自己的窗口。有没有办法每隔n毫秒将窗口发送到顶部?

编辑:我解决这个问题的方法是添加一个系统托盘图标,通过双击取消该过程。系统托盘图标不会被遮盖。谢谢所有回复的人。我读了一篇关于为什么没有“超级顶部”窗口的文章......它在逻辑上不起作用。

13 个答案:

答案 0 :(得分:148)

Form.TopMost将起作用,除非其他程序正在创建最顶层的窗口。

无法创建另一个进程的新顶部窗口未覆盖的窗口。 Raymond Chen explained为什么。

答案 1 :(得分:30)

我正在寻找使我的WinForms应用程序“永远在顶部”,但设置“TopMost”并没有为我做任何事情。我知道这是可能的,因为WinAmp会这样做(以及许多其他应用程序)。

我所做的是拨打“user32.dll”。我对此没有任何疑虑,而且效果很好。无论如何,这是一个选择。

首先,导入以下命名空间:

using System.Runtime.InteropServices;

在类声明中添加一些变量:

private static readonly IntPtr HWND_TOPMOST = new IntPtr(-1);
private const UInt32 SWP_NOSIZE = 0x0001;
private const UInt32 SWP_NOMOVE = 0x0002;
private const UInt32 TOPMOST_FLAGS = SWP_NOMOVE | SWP_NOSIZE;

为user32.dll函数添加原型:

[DllImport("user32.dll")] 
[return: MarshalAs(UnmanagedType.Bool)]
public static extern bool SetWindowPos(IntPtr hWnd, IntPtr hWndInsertAfter, int X, int Y, int cx, int cy, uint uFlags);

然后在你的代码中(我在Form_Load()中添加了调用),添加调用:

SetWindowPos(this.Handle, HWND_TOPMOST, 0, 0, 0, 0, TOPMOST_FLAGS);

希望有所帮助。 Reference

答案 2 :(得分:21)

如果“疯狂”意味着每个窗口都不断地从另一个窗口窃取焦点,TopMost将无法解决问题。

相反,请尝试:

CalledForm.Owner = CallerForm;
CalledForm.Show();

这将显示“孩子”形式,而不会窃取焦点。即使父母被激活或专注,子表单也将保留在其父表单之上。如果您已在所有者表单中创建子表单的实例,则此代码仅适用。否则,您可能必须使用API​​设置所有者。

答案 3 :(得分:15)

设置Form.TopMost

答案 4 :(得分:6)

将表单的.TopMost属性设置为true。

您可能不希望一直保持这种状态:在外部进程启动时设置它并在完成后将其放回。

答案 5 :(得分:5)

我解决这个问题的方法是制作一个带有取消选项的系统托盘图标。

答案 6 :(得分:5)

我有一个短暂的5分钟失误,我忘了像这样完整地指定表格:

  myformName.ActiveForm.TopMost = true;

但我真正想要的是这个!

  this.TopMost = true;

答案 7 :(得分:5)

以下代码使窗口始终保持在顶部并使其无框架。

using System;
using System.Drawing;
using System.Runtime.InteropServices;
using System.Windows.Forms;

namespace StayOnTop
{
    public partial class Form1 : Form
    {
        private static readonly IntPtr HWND_TOPMOST = new IntPtr(-1);
        private const UInt32 SWP_NOSIZE = 0x0001;
        private const UInt32 SWP_NOMOVE = 0x0002;
        private const UInt32 TOPMOST_FLAGS = SWP_NOMOVE | SWP_NOSIZE;

        [DllImport("user32.dll")]
        [return: MarshalAs(UnmanagedType.Bool)]
        public static extern bool SetWindowPos(IntPtr hWnd, IntPtr hWndInsertAfter, int X, int Y, int cx, int cy, uint uFlags);

        public Form1()
        {
            InitializeComponent();
            FormBorderStyle = FormBorderStyle.None;
            TopMost = true;
        }

        private void Form1_Load(object sender, EventArgs e)
        {
            SetWindowPos(this.Handle, HWND_TOPMOST, 100, 100, 300, 300, TOPMOST_FLAGS);
        }

        protected override void WndProc(ref Message m)
        {
            const int RESIZE_HANDLE_SIZE = 10;

            switch (m.Msg)
            {
                case 0x0084/*NCHITTEST*/ :
                    base.WndProc(ref m);

                    if ((int)m.Result == 0x01/*HTCLIENT*/)
                    {
                        Point screenPoint = new Point(m.LParam.ToInt32());
                        Point clientPoint = this.PointToClient(screenPoint);
                        if (clientPoint.Y <= RESIZE_HANDLE_SIZE)
                        {
                            if (clientPoint.X <= RESIZE_HANDLE_SIZE)
                                m.Result = (IntPtr)13/*HTTOPLEFT*/ ;
                            else if (clientPoint.X < (Size.Width - RESIZE_HANDLE_SIZE))
                                m.Result = (IntPtr)12/*HTTOP*/ ;
                            else
                                m.Result = (IntPtr)14/*HTTOPRIGHT*/ ;
                        }
                        else if (clientPoint.Y <= (Size.Height - RESIZE_HANDLE_SIZE))
                        {
                            if (clientPoint.X <= RESIZE_HANDLE_SIZE)
                                m.Result = (IntPtr)10/*HTLEFT*/ ;
                            else if (clientPoint.X < (Size.Width - RESIZE_HANDLE_SIZE))
                                m.Result = (IntPtr)2/*HTCAPTION*/ ;
                            else
                                m.Result = (IntPtr)11/*HTRIGHT*/ ;
                        }
                        else
                        {
                            if (clientPoint.X <= RESIZE_HANDLE_SIZE)
                                m.Result = (IntPtr)16/*HTBOTTOMLEFT*/ ;
                            else if (clientPoint.X < (Size.Width - RESIZE_HANDLE_SIZE))
                                m.Result = (IntPtr)15/*HTBOTTOM*/ ;
                            else
                                m.Result = (IntPtr)17/*HTBOTTOMRIGHT*/ ;
                        }
                    }
                    return;
            }
            base.WndProc(ref m);
        }

        protected override CreateParams CreateParams
        {
            get
            {
                CreateParams cp = base.CreateParams;
                cp.Style |= 0x20000; // <--- use 0x20000
                return cp;
            }
        }
    }
}

答案 8 :(得分:4)

您试图抑制其他应用程序的可见性是什么?你有没有调查过其他方法来达到你想要的效果?请在您的用户遇到如您所描述的流氓行为之前这样做:您尝试做的事情听起来更像是某些顽皮网站对浏览器窗口所做的事情......

至少尝试遵守Least Surprise的规则。用户希望能够确定大多数应用程序本身的z顺序。你不知道什么对他们来说最重要,所以如果你改变什么,你应该专注于推动其他应用程序,而不是推广自己的应用程序。

这当然比较棘手,因为Windows没有特别复杂的窗口管理器。两种方法表明了自己:

  1. enumerating top-level windows 并检查which process they belong todropping their z-order if so。 (我不确定是否 有框架方法 这些WinAPI功能。)
  2. 摆弄子进程权限以防止它访问桌面......但是在其他方法失败之前我不会尝试这个,因为子进程可能在需要用户交互时最终处于僵尸状态。

答案 9 :(得分:4)

为什么不将表单设为对话框:

myForm.ShowDialog();

答案 10 :(得分:3)

这是SetForegroundWindow的等价物:

form.Activate();

我见过人们在做奇怪的事情,如:

this.TopMost = true;
this.Focus();
this.BringToFront();
this.TopMost = false;

http://blog.jorgearimany.com/2010/10/win32-setforegroundwindow-equivalent-in.html

答案 11 :(得分:1)

我知道这是旧的,但我没有看到这种反应。

在窗口(xaml)中添加:

Deactivated="Window_Deactivated"

在Window_Deactivated背后的代码中:

private void Window_Deactivated(object sender, EventArgs e)
    {
        Window window = (Window)sender;
        window.Activate();
    }

这将使您的窗口保持最佳状态。

答案 12 :(得分:0)

基于clamum's答案和 Kevin Vuilleumier's关于引起该行为的另一个标志的评论,我进行了此切换,以在 ontop not之间切换顶部并按下按钮。

username:$apr1$h81U4v3.$8Msypa0Kx2hQ/C0948BuV1