本文介绍如何将窗口置于最顶层,以及解决在顶层显示时对锁屏登录界面的影响

一般情况下的窗口置顶,可以设置WPF窗口属性Topmost=true

也可以使用WIN32-SetWindowPos函数SetWindowPos 函数 (winuser.h) - Win32 apps | Microsoft Learn,设置窗口层级:

 1     /// <summary>设置窗口位置</summary>
2 /// <param name="hwnd">窗口句柄</param>
3 /// <param name="hWndInsertAfter">跟随的窗口句柄</param>
4 /// <param name="x">X轴坐标</param>
5 /// <param name="y">Y轴坐标</param>
6 /// <param name="width">宽</param>
7 /// <param name="height">高</param>
8 /// <param name="uFlags">标志位</param>
9 /// <returns></returns>
10 [DllImport("user32.dll", SetLastError = true)]
11 public static extern bool SetWindowPos(IntPtr hwnd, IntPtr hWndInsertAfter, int x, int y, int width, int height, uint uFlags);

hWndInsertAfter,需要置顶可以传入参数HWND_TOPMOST(-1)。设置后会在任务栏上方显示(注意:不是开始菜单显示时的任务栏,开始菜单显示后任务栏层级是超级高的,置顶层级需要再次提升,下面会讲到)

如果你软件的置顶需求是常驻,需要解决与其它置顶窗口的层级冲突、抢他们的层级,可以加个定时器:

 1     private nint _handle;
2 private void MainWindow_Loaded(object sender, RoutedEventArgs e)
3 {
4 _handle = new WindowInteropHelper(this).Handle;
5 SetWindowPos(_handle, -1, 0, 0, 0, 0, 1);
6 //定时器置顶
7 var timer = new Timer();
8 timer.Interval = 100;
9 timer.Elapsed += Timer_Elapsed;
10 timer.Start();
11 }
12 private void Timer_Elapsed(object? sender, System.Timers.ElapsedEventArgs e)
13 {
14 SetWindowPos(_handle, -1, 0, 0, 0, 0, 1);
15 }

当然,这种窗口置顶方案,遇上比你更流氓的软件就GG了,会抢来抢去。

最上层置顶还有一个方法,根据我们MVP毅仔提供的方案 让你的程序置顶到比系统界面都更上层,就像任务管理器/放大镜一样绝对置顶 - walterlv,我们简单补充整理:

1. 添加app.manifest,并修改requestedExecutionLevel为管理员启动权限、添加UI置顶权限,详细的可以了解 /MANIFESTUAC(将 UAC 信息嵌入到清单中) | Microsoft Learn

<requestedExecutionLevel level="requireAdministrator" uiAccess="true" />

这里的窗口置顶可以设置比系统界面更高的置顶,也就是说可以比一些系统级别的置顶还要高,效果同任务管理器的绝对置顶。UiAccess可以帮应用程序绕过用户界面保护级别、并将输入引导到桌面上的更高权限窗口

2. 给Windows设置属性ShowInTaskbar="True"、Topmost="True",

3. 添加程序签名

4. 将程序放在安装目录下C:\Program Files、C:\Program Files (x86)。确保应用程序是从受信任的位置启动的,因为 Windows 对 UIAccess 应用程序的启动位置有严格限制。

启动后,窗口层级就比Windows开始菜单以及设置置顶的任务管理器,都要高。窗口层级关系如下,桌面<一般应用窗口<Windows开始菜单<置顶的任务管理器<当前置顶应用Demo:

层级设置没问题。我们来说下这个方案的几个问题

1. Windows锁屏/登录界面,置顶窗口也会显示,影响了用户操作

解决:监听锁屏/解锁屏的事件,添加窗口Topmost修改

 1     public MainWindow()
2 {
3 InitializeComponent();
4 //当前登录的用户变化
5 SystemEvents.SessionSwitch += SystemEvents_SessionSwitch;
6 }
7 private void SystemEvents_SessionSwitch(object sender, SessionSwitchEventArgs e)
8 {
9 switch (e.Reason)
10 {
11 //解锁屏
12 case SessionSwitchReason.SessionUnlock:
13 Topmost = true;
14 break;
15 //锁屏
16 case SessionSwitchReason.SessionLock:
17 Topmost = false;
18 break;
19 }
20 }

锁屏后窗口层级降低效果:

2. 任务栏图标如果有需求需要隐藏的话,设置窗口ShowInTaskbar=false无法隐藏图标

这种情况下,我磨了下代码,可以这么操作:

1     int exStyle = GetWindowLong(hWnd, GWL_EXSTYLE);
2 // 设置窗口样式为工具窗口, 不在任务栏显示
3 exStyle |= WS_EX_TOOLWINDOW;
4 SetWindowLong(hWnd, GWL_EXSTYLE, exStyle);
5 //二次设置任务栏不显示
6 ShowInTaskbar = false;

使用SetWindowLong来设置窗口为工具窗口样式,然后更新窗口属性ShowInTaskbar=false:

WS_EX_TOOLWINDOW 样式 - 此扩展窗口样式用于创建工具窗口。Windows 不将此类工具窗口视为常规应用程序窗口,因此默认情况下不在任务栏中显示

ShowInTaskbar = false - WPF是通过设置ShowInTaskbar来实现不在任务栏中显示。

注意:需要俩个同时设置,有uiAccess的置顶应用才能隐藏任务栏

我猜测,是uiAccess会影响窗口样式的应用方式,而WS_EX_TOOLWINDOW结合ShowInTaskbar,明确告诉 WPF 不要在任务栏中显示此窗口,进一步确保了图标不显示出来。

此类场景置顶代码如下:

 1     public void SetTopmost()
2 {
3 IntPtr hWnd = _hWnd;
4 // 将窗口设置为顶层窗口
5 Topmost = true;
6
7 int exStyle = GetWindowLong(hWnd, GWL_EXSTYLE);
8 // 设置窗口样式为工具窗口, 不在任务栏显示
9 exStyle |= WS_EX_TOOLWINDOW;
10 SetWindowLong(hWnd, GWL_EXSTYLE, exStyle);
11 //二次设置任务栏不显示
12 ShowInTaskbar = false;
13 }

也可以看github仓库完整代码  kybs00/WindowsShowTopDemo,需要快速验证置顶可以用这个WindowShowTopDemo.exe

3. 根据小伙伴反馈,应用设置了uiAccess后,在此进程打开其它软件,其它软件通过调用SetParent实现相关功能时会失败

这个我验证了下确实如此。目前暂无解决方案,可以通过创建子进程、以进程通信去启动相关应用,来规避。

.NET 窗口置于最顶层的更多相关文章

  1. winform程序中将控件置于最顶层或最底层的方法

    有时,我们可能动态的添加控件,并准备将其置于对顶层或最底层.实现的方法有两个: 一种方法是在WinForm窗体中使用Controls控件集的SetChildIndex方法,该方法将子控件设定为指定的索 ...

  2. VC.【转】窗口置于前台并激活的方法

    1.VC 窗口置于前台并激活的方法 - CSDN博客.html https://blog.csdn.net/oXunFeng/article/details/52681279 2.(http://ww ...

  3. SetForegroundWindow以及 如何将一个某个窗口提到最顶层(转)

    http://hi.baidu.com/gookings/item/2b7912ca8d5b3625a0b50aa2 SetForegroundWindow 函数功能:该函数将创建指定窗口的线程设置到 ...

  4. C# 控件置于最顶层、最底层、隐藏、显示

    控件置于最顶层.最底层 pictureBox1.BringToFront();//将控件放置所有控件最前端 pictureBox1.SendToBack();//将控件放置所有控件最底端 控件隐藏.显 ...

  5. SetForegroundWindow、SetActiveWindow、SetFocus 如何将一个某个窗口提到最顶层

    http://hi.baidu.com/gookings/item/2b7912ca8d5b3625a0b50aa2 SetForegroundWindow 函数功能:该函数将创建指定窗口的线程设置到 ...

  6. WPF将窗口置于桌面下方(可用于动态桌面)

    WPF将窗口置于桌面下方(可用于动态桌面) 先来看一下效果: 界面元素很简单,就一个Button按钮,然后写个定时器,定时更新Button按钮中的内容为当前时间,下面来介绍下原理,和界面组成. 窗口介 ...

  7. 2016.5.30让窗口处于最顶层的方法,比TopMost灵活

    最简单的方法Form. Activate() 稍复杂的方法用API,目前没有看出比第一种方法有什么好处(可操作其它窗口,这就是好处2016.7.31) [System.Runtime.InteropS ...

  8. C# 控件置于最顶层、最底层

    btn.BringToFront();//将控件放置所有控件最前端 btn.SendToBack();//将控件放置所有控件最底端

  9. css 让div 置于最顶层而不被其他东西挡住

    今天遇到自己写的div被其他东西给挡住了,需要设置一个属性就成功了 设置:z-index:值:比如 z-index:999. 若值设置为为-1,代表为最底层. div的图层由div的style中的z- ...

  10. WPF Window背景半透明 ,蒙版操作实现

    原文:WPF Window背景半透明 ,蒙版操作实现 版权声明:本文为博主原创文章,未经博主允许不得转载. https://blog.csdn.net/BYH371256/article/detail ...

随机推荐

  1. Vue写一个图片轮播组件【转载】

    一.理清思路,理解需求和原理 1. 要写一个什么样的轮播? 在点击右侧箭头时,图片向左滑动到下一张:点击左侧箭头时,图片向右滑到下一张 点击下面的小圆点,滑到对应的图片,相应小圆点的样式也发生改变 要 ...

  2. 无套路领取《AI应用开发专栏》

    最近有些时间没有更新技术文章了,都在忙着写<AI应用开发入门>专栏,专栏已整理放到了github上,有兴趣的小伙伴可以移步github阅读,地址见文末. 1.为什么写这个文档 之前陆续写了 ...

  3. 无法访问k8s.gcr.io下载镜像问题解决办法

    部署K8S最大的难题是镜像下载,在国内无FQ环境情况下很难从k8s.gcr.io等镜像源里下载镜像. 这种情况下正确做法是: 直接指定国内镜像代理仓库(如阿里云代理仓库)进行镜像拉取下载. 成功拉取代 ...

  4. 鸿蒙Navigation入门使用

    Navigation组件适用于模块内和跨模块的路由切换,通过组件级路由能力实现更加自然流畅的转场体验,并提供多种标题栏样式来呈现更好的标题和内容联动效果.一次开发,多端部署场景下,Navigation ...

  5. 【一步步开发AI运动小程序】八、利用body-calc进行姿态识别

    随着人工智能技术的不断发展,阿里体育等IT大厂,推出的"乐动力"."天天跳绳"AI运动APP,让云上运动会.线上运动会.健身打卡.AI体育指导等概念空前火热.那 ...

  6. Myeclipse优化:自动转义字符串中的特殊字符

    在Myeclipse或者Eclipse中,将一段带引号(或其他的需要转义)字符串黏贴到引号中,双引号默认不会自动转义,手工一个一个去转义(变成\")的话实在是费事,这里记录一下让Myecli ...

  7. linux虚拟ip原理

    在 Linux 中,虚拟 IP(Virtual IP,VIP)是指一组与物理网络接口卡 (NIC) 绑定的虚拟 IP 地址,这些 IP 地址并不是物理上存在的,而是通过软件模拟实现的. Linux 实 ...

  8. IntelliJ IDEA 中 ctrl + w 一键选中双引号中的字符串内容

    记录下,之前一直知道在 IntelliJ IDEA 中快速选中一个词的快捷键是 ctrl + w,可是有时我们想一键选中双引号中的字符串内容,正好这个字符串中的内容有各种特殊字符,比如",& ...

  9. Advanced .NET Remoting: 第 9 章 4.改变编程模型

    Advanced .NET Remoting: 第 9 章 4.改变编程模型 前面的所有连接器在 .NET Remoting 应用程序的服务器端和客户端两方面增强功能.可插拔的连接器架构不仅支持创建连 ...

  10. 加密Python项目代码之把Django或Flask项目打包成exe

    目录 python代码仿泄露方案 -方案一:启动起来,把源代码删除 -方案二:pipinstaller 打包成可执行文件 -方案三:做到docker镜像中--->运行容器--->-e pa ...