首页 > 其他分享 >【WPF踩坑】-后台窗口切换到前台

【WPF踩坑】-后台窗口切换到前台

时间:2025-01-03 13:33:29浏览次数:7  
标签:WindowState 窗口 Topmost Win32 window 前台 后台 WPF

引入

在开发WPF应用时,你可能会需要把后台窗体切换到前台。

就是有A和B两个窗口,用户把B窗口最小化了,但是现在你需要把的B窗口用代码的方式切换到前台,而B窗口放在A窗口后面

过去的做法

可能你会看到很多文章,告诉你直接像下面一样,执行这段代码即可:

window.Activate()

但实际上,这行代码会一点作用也没有。

现在的做法

经过一段时间的检索和排查,我们终于在lindexi大佬的博客中,找到了解决方案。

[WPF 让窗口激活作为前台最上层窗口的方法]

 var interopHelper = new WindowInteropHelper(window);
 var thisWindowThreadId = Win32.User32.GetWindowThreadProcessId(interopHelper.Handle, IntPtr.Zero);
 var currentForegroundWindow = Win32.User32.GetForegroundWindow();
 var currentForegroundWindowThreadId = Win32.User32.GetWindowThreadProcessId(currentForegroundWindow, IntPtr.Zero);

            // [c# - Bring a window to the front in WPF - Stack Overflow](https://stackoverflow.com/questions/257587/bring-a-window-to-the-front-in-wpf )
            // [SetForegroundWindow的正确用法 - 子坞 - 博客园](https://www.cnblogs.com/ziwuge/archive/2012/01/06/2315342.html )
            /*
                 1.得到窗口句柄FindWindow 
                2.切换键盘输入焦点AttachThreadInput 
                3.显示窗口ShowWindow(有些窗口被最小化/隐藏了) 
                4.更改窗口的Zorder,SetWindowPos使之最上,为了不影响后续窗口的Zorder,改完之后,再还原 
                5.最后SetForegroundWindow 
             */
            Win32.User32.AttachThreadInput(currentForegroundWindowThreadId, thisWindowThreadId, true);

            window.Show();
            window.Activate();
            // 去掉和其他线程的输入链接
            Win32.User32.AttachThreadInput(currentForegroundWindowThreadId, thisWindowThreadId, false);

            // 用于踢掉其他的在上层的窗口
            window.Topmost = true;
            window.Topmost = false;

引入Win32 Api之后,确实解决了大部分问题。

存在的问题

当然,大佬也在博客里面说了,会有坑。

这篇文章还能水,那肯定是我踩到坑了。

Topmost问题

首先,会遇到Topmost问题。

代码中因为要使用Topmost,踢掉之前的上层窗口。

但是在第二次取消设置Topmost的时候,Topmost = false有概率不生效。

切换前台失效问题

正如大佬所说,因为可能会有坑,所以不一定100%工作。

而这个问题,在于后台的窗口如果已经最大化,那么后台窗体就不会切换到前台。

我的改进

Topmost问题

解决Topmost问题,需要在激活窗体的时候演示设置Topmost = false,这样能够避免同时设置Topmost 的值而不生效。

Task.Run(async () =>
    {
        await Task.Delay(200);
        KyrioGUI.RunOnUIThread(() =>
           {
                window.Topmost = false;
                //window.WindowState = WindowState.Maximized;
            });
    });

做个异步Lambda,然后await Task.Delay,然后在同步线程中执行取消设置Topmost 即可。

KyrioGUI.RunOnUIThread是我自己实现的切换到UI线程执行的代码,你也可以用SynchronizationContext.Current.Send来代替,最终效果是一样的。

切换前台失效问题

至于为什么,可能需要由大佬再研究了,我的直觉告诉我这部分的坑都来自Win32部分。

不过我没时间深究这些细节了,我给出的解决办法就是:

 //
 //
 AttachThreadInput(currentWindowThreadID, threadID, true);
            
 //window.Show();
 window.Activate();
            
 AttachThreadInput(currentWindowThreadID, threadID, false);
            
 // 用于踢掉其他的在上层的窗口
 window.Topmost = true;
 window.WindowState = WindowState.Normal;

在设置window.Topmost = true之后,紧接着设置window.WindowState = WindowState.Normal,让后台窗口变为普通模式,而不是最大化。

这样代码就可以正常工作了。

至于为什么我注释掉window.Show();,是因为调用这个函数的时候,DEBUG模式下,直接卡住了,连VS都卡住了。

注释掉之后一切恢复正常,代码也不会不工作。

后续

和lindexi大佬反馈了这个坑

标签:WindowState,窗口,Topmost,Win32,window,前台,后台,WPF
From: https://www.cnblogs.com/luoyisi/p/18649972

相关文章

  • WPF通过外部资源文件为主页面控件编写样式
    1.增加外部样式文件,添加资源词典(WPF)文件创建公共样式文件GlobalStyles.xaml 编写样式文件,以<style>标记开头,TargetType属性为控件类型,如按钮“Button”,单选按钮“RadioButton”等,x:Key属性自定义命名,控件在引用属性的时候需将Style属性设置为{StaticResourcekey属性}......
  • WPF DevExpress按住鼠标下拉滑动列表功能
    usingSystem;usingSystem.Windows;usingSystem.Windows.Controls;usingSystem.Windows.Input;usingSystem.Windows.Media;usingSystem.Windows.Threading;usingDevExpress.Xpf.Grid;namespaceClient{publicclassAutoScrollHelper{publicA......
  • 升级后代理后台与宝塔读取的实际配置不符
    升级后代理后台与宝塔读取的实际配置不符,通常是由于以下几个原因导致的:磁盘分区误解:初次接触Linux系统的用户可能会混淆系统盘(通常是根目录/)与数据盘(如/home)。实际上,系统盘主要用于存放操作系统及相关软件,而数据盘用于存储用户数据。因此,当您认为是在扩展数据盘时,实际上可能是......
  • 基于springboot的医院后台管理系统的设计与实现
      运行环境环境说明:开发语言:java框架:springboot,vueJDK版本:JDK1.8数据库:mysql5.7+(推荐5.7,8.0也可以)数据库工具:Navicat11+开发软件:idea/eclipse(推荐idea)Maven包:Maven3.3.9+系统实现系统实现这个章节的内容主要还是展示系统的功能界面设计效果,在实现系统......
  • WPF System.WIndows.Forms add wpf control
    1.NewSystem.Windows.Formsproject;2.Addreference C:\ProgramFiles\ReferenceAssemblies\Microsoft\Framework\v3.0\WindowsFormsIntegration.dll3.DragElementHostfromToolboxtoWindowsForms  4.AddreferencePresentationCore.dll;AddreferenceP......
  • WPF add System.Windows.Forms.PropertyGrid via WindowsFormsHost
    1.AddreferenceSystem.Windows.Forms.dll;2.Addreference C:\ProgramFiles\ReferenceAssemblies\Microsoft\Framework\v3.0\WindowsFormsIntegration.dll3.//xaml<Windowx:Class="WpfApp131.MainWindow"xmlns="http://schemas.mi......
  • WPF call Windows.Forms.PropertyGrid in xaml
    1.AddreferenceSystem.Windows.Forms;2.Addreference C:\ProgramFiles\ReferenceAssemblies\Microsoft\Framework\v3.0\WindowsFormsIntegration.dll3.<Windowx:Class="WpfApp132.MainWindow"xmlns="http://schemas.microsoft.com......
  • Spread WPF 18.0 FIX
    SpreadSheetDesignerTheSpreadSheetDesignerisastandalonetoolthatallowsyoutoeasilycreateaspreadsheetcomponent.Whetheryouaredesigningacompletespreadsheetcomponentorsimplycustomizingaportionofanexistingspreadsheetcomponent,t......
  • 【WPF学习】第五十四章 关键帧动画
    【WPF学习】第五十四章关键帧动画 到目前为止,看到的所有动画都使用线性插值从起点到终点。但如果需要创建具有多个分段的动画和不规则移动的动画。例如,可能希望创建一个动画,快速地将一个元素滑入到视图中,然后慢慢地将它移到正确位置。可通过创建两个连续的动画,并使用Beg......
  • 【WPF学习】第十六章 键盘输入
    【WPF学习】第十六章键盘输入 当用户按下键盘上的一个键时,就会发生一系列事件。下表根据他们的发生顺序列出了这些事件:表所有元素的键盘事件(按顺序) 键盘处理永远不会像上面看到的这么简单。一些控件可能会挂起这些事件中的某些事件,从而可执行自己更特殊的键......