首页 > 其他分享 >Winform ShowDialog如何让先前Show的窗体可以交互

Winform ShowDialog如何让先前Show的窗体可以交互

时间:2023-07-03 11:33:54浏览次数:33  
标签:IntPtr HandleRef currentForm Show 窗体 ShowDialog owner new null

背景描述

最近项目中有一个需求,全局有一个共用的窗体,能够打开不同模块的报告,由于需要兼容不同模块,代码复杂,启动速度慢。优化方案为将窗体启动时就创建好,需要查看报告时,使用此单例弹窗加载不同模块下的报告。

原项目模块是通过在主框架(Form1)下加载不同Tab页实现的,因此查看报告弹窗(Form2)是非模态Show出来。后来业务要求新加入一个模块,模块页面是通过模态方式呈现(Form3),即ShowDialog的方式。

这就有一个问题,如果用户在Form1下先打开Form2,然后又需要在Form3下打开Form2,此时Form2是无法操作的。如下:

解决思路

这个问题和winform设计有关,只能去看看winform源代码是如何区别处理Show和ShowDialog。

看看反编译后的代码: Show:
 1 public void Show(IWin32Window owner)
 2 {
 3     if (owner == this)
 4     {
 5         throw new InvalidOperationException(SR.GetString("OwnsSelfOrOwner", "Show"));
 6     }
 7 
 8     if (base.Visible)
 9     {
10         throw new InvalidOperationException(SR.GetString("ShowDialogOnVisible", "Show"));
11     }
12 
13     if (!base.Enabled)
14     {
15         throw new InvalidOperationException(SR.GetString("ShowDialogOnDisabled", "Show"));
16     }
17 
18     if (!TopLevel)
19     {
20         throw new InvalidOperationException(SR.GetString("ShowDialogOnNonTopLevel", "Show"));
21     }
22 
23     if (!SystemInformation.UserInteractive)
24     {
25         throw new InvalidOperationException(SR.GetString("CantShowModalOnNonInteractive"));
26     }
27 
28     if (owner != null && ((int)UnsafeNativeMethods.GetWindowLong(new HandleRef(owner, Control.GetSafeHandle(owner)), -20) & 8) == 0 && owner is Control)
29     {
30         owner = ((Control)owner).TopLevelControlInternal;
31     }
32 
33     IntPtr activeWindow = UnsafeNativeMethods.GetActiveWindow();
34     IntPtr intPtr = (owner == null) ? activeWindow : Control.GetSafeHandle(owner);
35     IntPtr zero = IntPtr.Zero;
36     base.Properties.SetObject(PropDialogOwner, owner);
37     Form ownerInternal = OwnerInternal;
38     if (owner is Form && owner != ownerInternal)
39     {
40         Owner = (Form)owner;
41     }
42 
43     if (intPtr != IntPtr.Zero && intPtr != base.Handle)
44     {
45         if (UnsafeNativeMethods.GetWindowLong(new HandleRef(owner, intPtr), -8) == base.Handle)
46         {
47             throw new ArgumentException(SR.GetString("OwnsSelfOrOwner", "show"), "owner");
48         }
49 
50         zero = UnsafeNativeMethods.GetWindowLong(new HandleRef(this, base.Handle), -8);
51         UnsafeNativeMethods.SetWindowLong(new HandleRef(this, base.Handle), -8, new HandleRef(owner, intPtr));
52     }
53 
54     base.Visible = true;
55 }
View Code

  

ShowDialog:
  1 public DialogResult ShowDialog(IWin32Window owner)
  2 {
  3     if (owner == this)
  4     {
  5         throw new ArgumentException(SR.GetString("OwnsSelfOrOwner", "showDialog"), "owner");
  6     }
  7 
  8     if (base.Visible)
  9     {
 10         throw new InvalidOperationException(SR.GetString("ShowDialogOnVisible", "showDialog"));
 11     }
 12 
 13     if (!base.Enabled)
 14     {
 15         throw new InvalidOperationException(SR.GetString("ShowDialogOnDisabled", "showDialog"));
 16     }
 17 
 18     if (!TopLevel)
 19     {
 20         throw new InvalidOperationException(SR.GetString("ShowDialogOnNonTopLevel", "showDialog"));
 21     }
 22 
 23     if (Modal)
 24     {
 25         throw new InvalidOperationException(SR.GetString("ShowDialogOnModal", "showDialog"));
 26     }
 27 
 28     if (!SystemInformation.UserInteractive)
 29     {
 30         throw new InvalidOperationException(SR.GetString("CantShowModalOnNonInteractive"));
 31     }
 32 
 33     if (owner != null && ((int)UnsafeNativeMethods.GetWindowLong(new HandleRef(owner, Control.GetSafeHandle(owner)), -20) & 8) == 0 && owner is Control)
 34     {
 35         owner = ((Control)owner).TopLevelControlInternal;
 36     }
 37 
 38     CalledOnLoad = false;
 39     CalledMakeVisible = false;
 40     CloseReason = CloseReason.None;
 41     IntPtr capture = UnsafeNativeMethods.GetCapture();
 42     if (capture != IntPtr.Zero)
 43     {
 44         UnsafeNativeMethods.SendMessage(new HandleRef(null, capture), 31, IntPtr.Zero, IntPtr.Zero);
 45         SafeNativeMethods.ReleaseCapture();
 46     }
 47 
 48     IntPtr intPtr = UnsafeNativeMethods.GetActiveWindow();
 49     IntPtr intPtr2 = (owner == null) ? intPtr : Control.GetSafeHandle(owner);
 50     IntPtr zero = IntPtr.Zero;
 51     base.Properties.SetObject(PropDialogOwner, owner);
 52     Form ownerInternal = OwnerInternal;
 53     if (owner is Form && owner != ownerInternal)
 54     {
 55         Owner = (Form)owner;
 56     }
 57 
 58     try
 59     {
 60         SetState(32, value: true);
 61         dialogResult = DialogResult.None;
 62         CreateControl();
 63         if (intPtr2 != IntPtr.Zero && intPtr2 != base.Handle)
 64         {
 65             if (UnsafeNativeMethods.GetWindowLong(new HandleRef(owner, intPtr2), -8) == base.Handle)
 66             {
 67                 throw new ArgumentException(SR.GetString("OwnsSelfOrOwner", "showDialog"), "owner");
 68             }
 69 
 70             zero = UnsafeNativeMethods.GetWindowLong(new HandleRef(this, base.Handle), -8);
 71             UnsafeNativeMethods.SetWindowLong(new HandleRef(this, base.Handle), -8, new HandleRef(owner, intPtr2));
 72         }
 73 
 74         try
 75         {
 76             if (dialogResult == DialogResult.None)
 77             {
 78                 Application.RunDialog(this);
 79             }
 80         }
 81         finally
 82         {
 83             if (!UnsafeNativeMethods.IsWindow(new HandleRef(null, intPtr)))
 84             {
 85                 intPtr = intPtr2;
 86             }
 87 
 88             if (UnsafeNativeMethods.IsWindow(new HandleRef(null, intPtr)) && SafeNativeMethods.IsWindowVisible(new HandleRef(null, intPtr)))
 89             {
 90                 UnsafeNativeMethods.SetActiveWindow(new HandleRef(null, intPtr));
 91             }
 92             else if (UnsafeNativeMethods.IsWindow(new HandleRef(null, intPtr2)) && SafeNativeMethods.IsWindowVisible(new HandleRef(null, intPtr2)))
 93             {
 94                 UnsafeNativeMethods.SetActiveWindow(new HandleRef(null, intPtr2));
 95             }
 96 
 97             SetVisibleCore(value: false);
 98             if (base.IsHandleCreated)
 99             {
100                 if (OwnerInternal != null && OwnerInternal.IsMdiContainer)
101                 {
102                     OwnerInternal.Invalidate(invalidateChildren: true);
103                     OwnerInternal.Update();
104                 }
105 
106                 DestroyHandle();
107             }
108 
109             SetState(32, value: false);
110         }
111     }
112     finally
113     {
114         Owner = ownerInternal;
115         base.Properties.SetObject(PropDialogOwner, null);
116     }
117 
118     return DialogResult;
119 }
View Code

 

关键代码为:
1 if (dialogResult == DialogResult.None)
2 {
3     Application.RunDialog(this);
4 }

 

顺着找:
1 internal static void RunDialog(Form form)
2 {
3     Application.ThreadContext.FromCurrent().RunMessageLoop(4, new Application.ModalApplicationContext(form));
4 }

 

再看看RunMessageLoop:
 1 internal void RunMessageLoop(int reason, ApplicationContext context)
 2 {
 3     IntPtr userCookie = IntPtr.Zero;
 4     if (Application.useVisualStyles)
 5     {
 6         userCookie = UnsafeNativeMethods.ThemingScope.Activate();
 7     }
 8     try
 9     {
10         this.RunMessageLoopInner(reason, context);
11     }
12     finally
13     {
14         UnsafeNativeMethods.ThemingScope.Deactivate(userCookie);
15     }
16 }

 

    找到Inner代码:
  1 private void RunMessageLoopInner(int reason, ApplicationContext context)
  2 {
  3     if (reason == 4 && !SystemInformation.UserInteractive)
  4     {
  5         throw new InvalidOperationException(SR.GetString("CantShowModalOnNonInteractive"));
  6     }
  7     if (reason == -1)
  8     {
  9         this.SetState(8, false);
 10     }
 11     if (Application.ThreadContext.totalMessageLoopCount++ == 0)
 12     {
 13         Application.ThreadContext.baseLoopReason = reason;
 14     }
 15     this.messageLoopCount++;
 16     if (reason == -1)
 17     {
 18         if (this.messageLoopCount != 1)
 19         {
 20             throw new InvalidOperationException(SR.GetString("CantNestMessageLoops"));
 21         }
 22         this.applicationContext = context;
 23         this.applicationContext.ThreadExit += this.OnAppThreadExit;
 24         if (this.applicationContext.MainForm != null)
 25         {
 26             this.applicationContext.MainForm.Visible = true;
 27         }
 28         DpiHelper.InitializeDpiHelperForWinforms();
 29         AccessibilityImprovements.ValidateLevels();
 30     }
 31     Form form = this.currentForm;
 32     if (context != null)
 33     {
 34         this.currentForm = context.MainForm;
 35     }
 36     bool flag = false;
 37     bool flag2 = false;
 38     HandleRef hWnd = new HandleRef(null, IntPtr.Zero);
 39     if (reason == -2)
 40     {
 41         flag2 = true;
 42     }
 43     if (reason == 4 || reason == 5)
 44     {
 45         flag = true;
 46         bool flag3 = this.currentForm != null && this.currentForm.Enabled;
 47         this.BeginModalMessageLoop(context);
 48         hWnd = new HandleRef(null, UnsafeNativeMethods.GetWindowLong(new HandleRef(this.currentForm, this.currentForm.Handle), -8));
 49         if (hWnd.Handle != IntPtr.Zero)
 50         {
 51             if (SafeNativeMethods.IsWindowEnabled(hWnd))
 52             {
 53                 SafeNativeMethods.EnableWindow(hWnd, false);
 54             }
 55             else
 56             {
 57                 hWnd = new HandleRef(null, IntPtr.Zero);
 58             }
 59         }
 60         if (this.currentForm != null && this.currentForm.IsHandleCreated && SafeNativeMethods.IsWindowEnabled(new HandleRef(this.currentForm, this.currentForm.Handle)) != flag3)
 61         {
 62             SafeNativeMethods.EnableWindow(new HandleRef(this.currentForm, this.currentForm.Handle), flag3);
 63         }
 64     }
 65     try
 66     {
 67         if (this.messageLoopCount == 1)
 68         {
 69             WindowsFormsSynchronizationContext.InstallIfNeeded();
 70         }
 71         if (flag && this.currentForm != null)
 72         {
 73             this.currentForm.Visible = true;
 74         }
 75         if ((!flag && !flag2) || this.ComponentManager is Application.ComponentManager)
 76         {
 77             bool flag4 = this.ComponentManager.FPushMessageLoop((IntPtr)this.componentID, reason, 0);
 78         }
 79         else if (reason == 2 || reason == -2)
 80         {
 81             bool flag4 = this.LocalModalMessageLoop(null);
 82         }
 83         else
 84         {
 85             bool flag4 = this.LocalModalMessageLoop(this.currentForm);
 86         }
 87     }
 88     finally
 89     {
 90         if (flag)
 91         {
 92             this.EndModalMessageLoop(context);
 93             if (hWnd.Handle != IntPtr.Zero)
 94             {
 95                 SafeNativeMethods.EnableWindow(hWnd, true);
 96             }
 97         }
 98         this.currentForm = form;
 99         Application.ThreadContext.totalMessageLoopCount--;
100         this.messageLoopCount--;
101         if (this.messageLoopCount == 0)
102         {
103             WindowsFormsSynchronizationContext.Uninstall(false);
104         }
105         if (reason == -1)
106         {
107             this.Dispose(true);
108         }
109         else if (this.messageLoopCount == 0 && this.componentManager != null)
110         {
111             this.RevokeComponent();
112         }
113     }
114 }
View Code

 

关键代码:
 1 if (reason == 4 || reason == 5)
 2 {
 3         flag = true;
 4         bool flag3 = this.currentForm != null && this.currentForm.Enabled;
 5         this.BeginModalMessageLoop(context);
 6         hWnd = new HandleRef(null, UnsafeNativeMethods.GetWindowLong(new HandleRef(this.currentForm, this.currentForm.Handle), -8));
 7         if (hWnd.Handle != IntPtr.Zero)
 8         {
 9             if (SafeNativeMethods.IsWindowEnabled(hWnd))
10             {
11                 SafeNativeMethods.EnableWindow(hWnd, false);
12             }
13             else
14             {
15                 hWnd = new HandleRef(null, IntPtr.Zero);
16             }
17         }
18         if (this.currentForm != null && this.currentForm.IsHandleCreated && SafeNativeMethods.IsWindowEnabled(new HandleRef(this.currentForm, this.currentForm.Handle)) != flag3)
19         {
20             SafeNativeMethods.EnableWindow(new HandleRef(this.currentForm, this.currentForm.Handle), flag3);
21         }
22 }

 

这边的逻辑其实就是:如果启用模态弹窗,则先把所有窗体禁用,然后找到当前需要展示的窗体,启用它。 知道了原理,我们依葫芦画瓢即可:调用WinApi中的EnableWindow。 部分示例代码:
1 private void btnOpenOldForm_Click(object sender, EventArgs e)
2 {
3     OldFrom.Hide();
4     OldFrom.Show(this);
5     OldFrom.BringToFront();
6     var formhandle = OldFrom.Handle;
7     NativeMethodHelper.EnableWindow(new HandleRef(null, formhandle), true);
8 }

 

附上winapi帮助类:
 1 public class NativeMethodHelper
 2 {
 3     [DllImport("user32.dll", CharSet = CharSet.Auto, ExactSpelling = true)]
 4     public static extern IntPtr SetActiveWindow(HandleRef hWnd);
 5 
 6     [DllImport("user32.dll", CharSet = CharSet.Auto, EntryPoint = "GetWindowLongPtr")]
 7     public static extern IntPtr GetWindowLongPtr64(HandleRef hWnd, int nIndex);
 8 
 9     public static IntPtr SetWindowLong(HandleRef hWnd, int nIndex, HandleRef dwNewLong)
10     {
11         if (IntPtr.Size == 4)
12         {
13             return NativeMethodHelper.SetWindowLongPtr32(hWnd, nIndex, dwNewLong);
14         }
15         return NativeMethodHelper.SetWindowLongPtr64(hWnd, nIndex, dwNewLong);
16     }
17     [DllImport("user32.dll", CharSet = CharSet.Auto, EntryPoint = "SetWindowLong")]
18     public static extern IntPtr SetWindowLongPtr32(HandleRef hWnd, int nIndex, HandleRef dwNewLong);
19 
20     [DllImport("user32.dll", CharSet = CharSet.Auto, EntryPoint = "SetWindowLongPtr")]
21     public static extern IntPtr SetWindowLongPtr64(HandleRef hWnd, int nIndex, HandleRef dwNewLong);
22 
23     /// <summary>
24     /// 启用窗体
25     /// </summary>
26     /// <param name="hWnd"></param>
27     /// <param name="enable"></param>
28     /// <returns></returns>
29     [DllImport("user32.dll", CharSet = CharSet.Auto, ExactSpelling = true)]
30     public static extern bool EnableWindow(HandleRef hWnd, bool enable);
31 }

 

执行效果:

 

标签:IntPtr,HandleRef,currentForm,Show,窗体,ShowDialog,owner,new,null
From: https://www.cnblogs.com/6112562a/p/17522323.html

相关文章

  • winfrom 中子窗体控件受到父窗体字体大小控制的解决
    举例为winform添加选项卡,在选项卡添加UserControl或者一个Form后,运行却发现窗体没有完全显示,如下图:右侧的三个按钮只显示了1个半,在这个问题上纠结了很长时间,直到不间断的寻找控件的属性,发现了解决方式和问题所在。这个问题在于子窗体的缩放由父窗体的字体控制,只要修改子窗体的......
  • WPF Showdialog与DialogResult的注意事项
    我们知道如果要设置window.Showdialog()的返回值,需要设置window.DialogResult属性。但是设置window.DialogResult属性会自动触发close,如果window.DialogResult属性会触发Window_OnClosing事件privatevoidBtnCancel_Click(objectsender,RoutedEventArgse){......
  • ctfshow web259
    考察点:1,SSRF2,Cloudflare代理服务器3,CRLF4,原生类反序列化解题过程:分析代码<?phphighlight_file(__FILE__);//flag.php$xff=explode(',',$_SERVER['HTTP_X_FORWARDED_FOR']);//array_pop($xff);$ip=array_pop($xff);​if($ip!=='127.0.0.1......
  • SHOW_SPACE
       这是Oracle大神TOM写的一个好工具SHOW_SPACE;它实际上就是一个存储过程,这个存储过程可以很高效的分析空间使用情况,有了此工具,就不用再通过写SQL语句来看每条记录或表占用表空间的大小了,使用起来非常方便。一、创建存储过程createorreplaceprocedureshow_space(p_seg......
  • 在窗体中创建按钮组件
    importjavax.swing.*;publicclassJButtonTest1{publicstaticvoidmain(String[]args){JFrameframe=newJFrame();frame.setSize(500,500);frame.setDefaultCloseOperation(WindowConstants.EXIT_ON_CLOSE);//关闭窗体的默认布......
  • [C#] winform窗体分布类实现
     为Form1窗体添加一个partial属性的分布类,需要以下几步:1.使用VisualStudio创建你的新工程,包含窗体Form12.创建一个新文件,命名成这样的格式:Form1.Behind.cs3.新class编辑为partial属性5.保存全部并关闭VisualStudio6.使用记事本打开[.csproj]文件7.寻找以下字段:[cod......
  • 快讯 | ShowMeBug入选人力资源智享会《TPG红宝书》
    近日,ShowMeBug入选人力资源智享会《2022-2023 HR年度采购指南暨智享会人力资源供应商价值大奖分类榜单》,亦被称为《ThepurchasingGuide》,简称《TPG红宝书》(以下简称《红宝书》)。《红宝书》由人力资源智享会编写并发布,目的在于成为HR采购人力资源相关服务和产品的工具书,有效帮......
  • ctfshow web入门
    CTFshowweb入门命令执行web29<?php/*#-*-coding:utf-8-*-#@Author:h1xa#@Date:2020-09-0400:12:34#@LastModifiedby:h1xa#@LastModifiedtime:2020-09-0400:26:48#@email:[email protected]#@link:https://ctfer.com*/error_reporting(0......
  • ctfshow 极限命令执行
    极限命令执行1第一关<?php//本题灵感来自研究一直没做出来的某赛某题时想到的姿势,太棒啦~。//flag在根目录flag里,或者直接运行根目录getflagerror_reporting(0);highlight_file(__FILE__);if(isset($_POST['ctf_show'])){$ctfshow=$_POST['ctf_show'];if(......
  • ShowMeBug与极狐(GitLab)战略合作,推动DevOps人才高效甄选
    近日,ShowMeBug与领先的开放式一体化安全DevOps平台提供商极狐(GitLab)达成深度合作协议,双方将致力于共同打造具有行业强认可度以及高实用性的DevOps岗位题型,助力企业通过更为专业、标准的技术笔试题型,提升DevOps岗位人才筛选效率。极狐GitLab是面向中国市场的开放式一体化安全Dev......