代码之家  ›  专栏  ›  技术社区  ›  jle

如何使窗口在.NET中始终保持在最上面?

  •  76
  • jle  · 技术社区  · 15 年前

    我有一个C WinForms应用程序在另一个程序中运行宏。另一个程序会不断弹出窗口,通常让事情看起来,因为没有更好的词,疯狂。我想实现一个取消按钮,它将停止进程的运行,但我似乎无法让窗口保持在最上面。我怎么用C来做这个?

    编辑:我已经尝试了topmost=true;,但是另一个程序总是在上面弹出自己的窗口。有没有办法每隔n毫秒把我的窗口送到最上面?

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

    12 回复  |  直到 6 年前
        1
  •  144
  •   George Stocker NotMe    12 年前

    Form.TopMost 除非另一个程序正在创建最顶层的窗口,否则将工作。

    无法创建不被其他进程的最顶层窗口覆盖的窗口。雷蒙德陈 explained 为什么?

        2
  •  31
  •   clamum    9 年前

    我在搜索使我的WinForms应用程序“总是在最上面”,但设置“最上面”对我没有任何帮助。我知道这是可能的,因为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);
    

    然后在您的代码中(我以_Load()的形式添加了调用),添加调用:

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

    希望有帮助。 Reference

        3
  •  21
  •   Victor Stoddard    12 年前

    如果说“发疯”,你的意思是每个窗口都在从另一个窗口窃取焦点,那么Topmost不会解决这个问题。

    相反,尝试:

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

    这将显示“子”窗体,而不会窃取焦点。即使父窗体被激活或集中,子窗体也将保持在其父窗体之上。只有在您从所有者窗体中创建了子窗体的实例时,此代码才容易工作。否则,您可能需要使用API设置所有者。

        4
  •  15
  •   Reed Copsey    15 年前
        5
  •  6
  •   Joel Coehoorn    15 年前

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

    您可能不想一直这样做:当外部进程开始时设置它,当它结束时放回去。

        6
  •  5
  •   jle    15 年前

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

        7
  •  5
  •   Dave    7 年前

    我有一个短暂的5分钟的失误,我忘了详细说明表格如下:

      myformName.ActiveForm.TopMost = true;
    

    但我真正想要的是这个!

      this.TopMost = true;
    
        8
  •  4
  •   Pontus Gagge    15 年前

    您试图禁止的另一个应用程序是什么?你是否研究过其他达到你期望效果的方法?在让你的用户受到你所描述的这种无赖行为之前,请这样做:你想做的事情听起来很像某些淘气的网站用浏览器窗口做的事情……

    至少要坚持 Least Surprise . 用户希望能够确定大多数应用程序本身的z顺序。你不知道什么对他们来说最重要,所以如果你改变了任何东西,你应该集中精力在每件事情的背后推动另一个应用程序,而不是提升你自己的应用程序。

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

    1. enumerating top-level windows 并检查 which process they belong to , dropping their z-order if so . (我不确定 有框架方法用于 这些winapi函数。)
    2. 玩弄子进程权限以阻止它访问桌面…但在另一种方法失败之前,我不会尝试这样做,因为子进程可能会在需要用户交互的情况下以僵尸状态结束。
        9
  •  4
  •   Salim    9 年前

    为什么不将窗体设为对话框:

    myForm.ShowDialog();
    
        10
  •  4
  •   mrid    7 年前

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

    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;
                }
            }
        }
    }
    
        11
  •  3
  •   timbre timbre    8 年前

    以下是SetForegroundWindow等效值:

    form.Activate();
    

    我见过人们做一些奇怪的事情,比如:

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

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

        12
  •  1
  •   waitWhat    6 年前

    我知道这很古老,但我没有看到这种反应。

    在窗口(xaml)中添加:

    Deactivated="Window_Deactivated"
    

    在窗口的代码隐藏中,禁用:

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

    这会使你的窗户保持在上面。