如何使窗口始终位于.Net顶部?


92

我有一个在另一个程序中运行宏的C#winforms应用程序。另一个程序将不断弹出窗口,并且由于缺少更好的用词,通常使事情看起来很疯狂。我想实现一个取消按钮,该按钮将停止进程的运行,但是我似乎无法使窗口停留在顶部。如何在C#中执行此操作?

编辑:我已经尝试过TopMost = true; ,但其他程序始终在顶部弹出自己的窗口。有没有办法每n毫秒将我的窗口发送到顶部?

编辑:我解决此问题的方法是添加一个系统任务栏图标,该图标将通过双击取消该过程。系统任务栏图标没有被掩盖。谢谢所有答复。我阅读了有关为什么没有“超级在顶部”窗口的文章……从逻辑上讲,它是行不通的。


61
是的,每隔几毫秒设置一个计时器,将您的Form.TopMost设置为true。然后,为了使它有趣,当加载“ crazy”程序时,播放Mortal Kombat的音频片段“ FIGHT!”。:-P
BFree

2
您可能以为您的评论很有趣,您可能以为您可以嘲笑不好的做法。我的问题是创建一个上下文菜单,该菜单浮在带有flowlayoutpanel的表单上。仅当调用flowlayoutpanel的Activate()方法时,才能滚动它,在某些情况下Focus()还不够。您只是无法滚动它。即使它具有排他的topmost = true,这也会从contextmenu菜单中窃取焦点!正如任何明智的人所知,让您的winform应用程序以MTAThread模式运行并赋予每种形式它自己的线程是非常敬虔的,这使解决方案变得简单:
Traubenfuchs 2014年

1
看得出来,这是一个魔鬼:pastebin.com/sMJX0Yav它可以完美运行而不会闪烁,并且sleep(1)足以防止它消耗严重的性能。当他专注于上下文菜单时,谁仍在寻找任务管理器?一旦上下文菜单关闭,它有望运行到空的异常处理程序中并死亡。您可能会建立一个isDisposed中断。
Traubenfuchs

我刚刚在这里发布了针对此问题的解决方案:stackoverflow.com/questions/2546566/…–
kfn

@Traubenfuchs 由于跨线程操作异常,该操作将失败。应该工作。
facepalm42

Answers:


170

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

无法创建一个未被另一个进程的最顶层窗口覆盖的窗口。Raymond Chen 解释了原因。


10
在任何情况下,其他完成新手在2016年及以后看到这种情况,试试Form.ActiveForm.TopMost
魔鬼代言人

@ScottBeeson:很好。在这个充满活力的技术世界中,更新信息非常必要。谢谢:)。
Sandeep Kushwah

47

我正在搜索使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);

希望能有所帮助。参考


2
这不仅适用于WinForms应用程序,还适用于控制台窗口。好发现!
rojo 2016年

很好,可以确认这项工作。但是我如何能够将其改回首位呢?您可以共享一个HWND_BOTTOMMOST标志吗?
标记

很好的问题,如果您想在此最高功能和默认行为之间进行切换(例如,对于窗口行为,您有一个“始终在最前面”复选框)。我猜想也许有了正确的标志就可以了。如果您具有描述默认窗口行为的正确标志(例如SWP_DEFAULT = 0x0003),则可以使用这些标志再次调用“ SetWindowPos()”。我不确定 我没有调查。祝您好运,如果有人这样做,请在此处添加!
Clamum

这无法像往常一样在全屏游戏模式下工作
Sajitha Rathnayake,

2
@Mark是,有一个标志HWND_NOTOPMOST(= -2)。见docs.microsoft.com/en-us/windows/win32/api/winuser/...
凯文VUILLEUMIER

23

如果通过“发疯”来表示每个窗口都在相互窃取焦点,那么TopMost将无法解决问题。

相反,请尝试:

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

这将显示“孩子”形式,而不会引起关注。子窗体也将保留在其父窗体的顶部,即使该父窗体已被激活或聚焦。仅当您在所有者表单中创建了子表单的实例时,此代码才能轻松工作。否则,您可能必须使用API​​设置所有者。


1
非常感谢您,我已经使用了它,并且效果很好!
AvetisG 2015年

1
谢谢..正是我在寻找什么
Sameera Kumarasingha 2015年

设置CalledForm.Owner为自身(CalledForm)将导致System.ArgumentException:'已完成循环控制参考。控件不能由其自己拥有或作为其父控件。”
facepalm42

2
这就是为什么您使用CallerForm而不是CalledForm的原因:)
Jesper

16

设置Form.TopMost


我试过了,这...我需要继续做吗?“疯狂程序”将立即接管……
jle

2
否-如果您设置form.TopMost = true,它应该可以工作。“疯狂”程序还必须将其对话框设置为TopMost,在这种情况下,您不能覆盖它。
里德·科普西2009年

不公平的战斗。谢谢。
2009年

11

我经过了5分钟的时间,却忘了像这样完整地指定表格:

  myformName.ActiveForm.TopMost = true;

但是我真正想要的是这个!

  this.TopMost = true;

对我来说完美。如果(checkBox1.Checked == true){this.TopMost = true; } else {this.TopMost = false; }
yosh

对我来说非常完美。谢谢。
Levani Titberia

6

设置表格的 .TopMost属性为true。

您可能不想一直保持这种状态:在外部过程开始时进行设置,在结束时将其放回。


5

我解决此问题的方法是使系统托盘图标具有取消选项。


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

同意Alexan-是什么让您的程序最重要?似乎实际上它只是“ topmost = true”语句,在很多情况下都行不通。其余所有代码并没有真正解决问题。
Fhaab '17年

4

您要抑制可见性的其他应用程序是什么?您是否研究过其他达到预期效果的方法?在使您的用户遭受您描述的这种流氓行为之前,请先这样做:您尝试做的事情听起来像某些顽皮的网站对浏览器窗口所做的事情...

至少尝试遵守“ 最少惊喜 ”规则。用户期望自己能够确定大多数应用程序的z顺序。您不知道什么对他们最重要,因此,如果您进行了任何更改,则应着重于将其他应用程序推到一切之上,而不是推广自己的应用程序。

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

  1. 枚举顶级窗口 并检查它们属于哪个进程如果,则删除其z顺序。(我不确定这些WinAPI函数是否有框架方法。)
  2. 摆弄子进程权限以防止其访问桌面...但是在其他方法失败之前,我不会尝试这样做,因为子进程可能最终陷入僵尸状态,而需要用户交互。

4

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

myForm.ShowDialog();

1
是! 这就是我想要的。设置TopMost = true迫使我的表单位于包括chrome在内的所有内容之上,而实际上这只是一个设置框,我需要将其置于主表单之上。恭喜您,网际网路使用者。
MDMoore313 '16

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


如果我不希望我的窗口处于活动状态,而只想使其最顶层(信息性,非交互性),该怎么办?我之所以这样问,是因为实际上发出“ topmost = True”在我的情况下不起作用(它在系统上起作用,而在其他系统上不起作用)。
Fhaab '17年

发现此方法对我们有用:this.Show(); this.Activate(); this.BringToFront(); 但是此答案将我们带到了该解决方案。谢谢!
jibbs

1

我知道这已经很老了,但是我没有看到这个回应。

在窗口(xaml)中添加:

Deactivated="Window_Deactivated"

在Window_Deactivated后面的代码中:

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

这将使您的窗口保持顶部。


1
您没有看到此响应,因为问题与winform有关。
动能的

1

基于clamum的答案,凯文VUILLEUMIER的有关负责行为的其他标志的评论,我做了这个拨动那之间切换上顶不顶按下一个按钮。

private void button1_Click(object sender, EventArgs e)
    {
        if (on)
        {
            button1.Text = "yes on top";
            IntPtr HwndTopmost = new IntPtr(-1);
            SetWindowPos(this.Handle, HwndTopmost, 0, 0, 0, 0, TopmostFlags);
            on = false;
        }
        else
        {
            button1.Text = "not on top";
            IntPtr HwndTopmost = new IntPtr(-2);
            SetWindowPos(this.Handle, HwndTopmost, 0, 0, 0, 0, TopmostFlags);
            on = true;
        }
    }
By using our site, you acknowledge that you have read and understand our Cookie Policy and Privacy Policy.
Licensed under cc by-sa 3.0 with attribution required.