Winform ShowDialog如何让先前Show的窗体可以交互
背景描述
最近项目中有一个需求,全局有一个共用的窗体,能够打开不同模块的报告,由于需要兼容不同模块,代码复杂,启动速度慢。优化方案为将窗体启动时就创建好,需要查看报告时,使用此单例弹窗加载不同模块下的报告。
原项目模块是通过在主框架(Form1)下加载不同Tab页实现的,因此查看报告弹窗(Form2)是非模态Show出来。后来业务要求新加入一个模块,模块页面是通过模态方式呈现(Form3),即ShowDialog的方式。
这就有一个问题,如果用户在Form1下先打开Form2,然后又需要在Form3下打开Form2,此时Form2是无法操作的。如下:

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

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 }

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

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

Winform ShowDialog如何让先前Show的窗体可以交互的更多相关文章
- WinForm中新开一个线程操作 窗体上的控件(跨线程操作控件)
最近在做一个winform的小软件(抢票的...).登录窗体要从远程web页面获取一些数据,为了不阻塞登录窗体的显示,开了一个线程去加载数据远程的数据,会报一个错误"线程间操作无效: 从不是 ...
- [WinForm] 使用反射将业务对象绑定到窗体或控件容器
在WebForm中,可以使用反射将业务对象绑定到 ASP.NET 窗体控件.最近做Winform项目,也参考WebForm中的代码实现同样的功能. Winform没有提供类似WebForm中的 ...
- WinForm 之 程序启动不显示主窗体
在 WinForm 程序启动时,不显示主窗体的实现方法主要有以下5种,第五种最简单,而且效果也不错,第四种方法也值得推荐. 实例代码如下: //隐藏窗体的方法1/5:不指定任何窗体为主窗体 //注意: ...
- Winform中怎样根据Name获取同窗体的控件
场景 在同一个Winform窗体中,点击一个Button按钮时, 获取同窗体的其他控件的属性. 首先需要对要获取的控件赋予Name属性,然后就可以通过Name进行获取. 实现 在Button的点击事件 ...
- Winform 在高分变率显示器中窗体变模糊配置方式
我们知道 Winform 前身与 XP 系统 同一时代出生 , 那时候显示器还是LCD 和 大头机 ,显示器普遍 96 DPI . 随着显示器质量改善,2K 屏, 4K屏普及,DPI 达 19 ...
- winform下自绘提示框风格窗体
昨天分享了一个环形滚动条控件,今天分享一个提示框风格的窗体.代码如下: /// <summary> /// 继承自Form,但将FormBorderStyle设置为None /// < ...
- win7 C# winForm编程 savefiledialog 不能弹出保存窗体
public void ResMsg() { while (isRecMsg) { //准备一个数组 准备接收 ...
- winform showDialog() 退出问题
今日发现: 当返回值为Dialog.OK时,会自动退出,不需要this.close().别的返回值仍需要.
- 浅谈delphi创建Windows服务程序与窗体实现交互
我想实现的功能是创建一个服务程序,然后在服务Start时动态创建一个窗体Form,然后把Form缩小时变成TrayIcon放在Windows托盘上. 我在服务程序的OnStart事件中写到 Start ...
- LayUI 子父窗体的交互
---恢复内容开始--- 收到的工作是将一个ERP的窗体程序改为网页实现,所以就肯定需要弹框来选择(如:物料编码.部门.业务员等等) 本文采取的前段框架是LayUI. layUI的官网API网址:ht ...
随机推荐
- Reverse the Rivers 题解
原题链接https://codeforces.com/problemset/problem/2036/E (暂时不会弄翻译,所以不上原题了) 说一下我对题意的理解吧 有n个国家,每个国家有k个区域,用 ...
- 从底层源码深入分析Spring的IoC容器初始化过程
IOC容器的初始化整体过程 Spring是如何实现将资源配置(以xml配置为例)通过加载,解析,生成BeanDefination并注册到IoC容器中的?这主要会经过以下 4 步: 从XML中读取配置文 ...
- Delon ACL
Delon ACL delon ACL Alain acl 路由守卫 使用 ACLService 核心是 ACLService,See:https://github.com/ng-alain/delo ...
- 在 ASP.NET Core 2.1 之后与 HttpClient 工厂一起使用 Polly
在 ASP.NET Core 2.1 之后与 HttpClient 工厂一起使用 Polly 在 ASP.NET Core 2.1 中提供的 HttpClient factory 提供了一种预配置 H ...
- 企架布道:中电金信应邀出席2023佛山敏捷之旅暨DevOps Meetup
近日,2023佛山敏捷之旅暨DevOps Meetup活动顺利举行,本次活动以助力大湾区金融和互联网企业敏捷DevOps实施和效能提升为主题,共设立 2个会场,16个话题分享,200余位金融.互联网企 ...
- Elm 和 Jetpack Compose 殊途同归及 MVVM 缺点分析
Html.lazy · An Introduction to Elm 可能搞 vdom 的都会到 lazy renderer 这一步,react 可能也可以这么搞或者已经这么搞了我不知道,Elm 提到 ...
- Postgresql使用触发器实现同步插入两张表
在有一个陈旧的系统的情况下,如果升级API可以优先使用微服务的形式,将数据库进行独立拆分,将原来的数据库原原本本地固定在旧系统中,然后在独立的微服务中运行与部署新系统. 如果原有的数据需要在更换结构的 ...
- JSchException: Algorithm negotiation fail问题解决之路
最近一个需求用到了SFTP上传功能,同事之前已经封装好了SFTP工具类,用的是JSch,本着不要重复造轮子的想法,就直接拿来用了.交代下环境,JDK为1.7,JSch版本为0.1.51.自测通过.测试 ...
- Datawhale 2025冬令营第二弹!!😊自己微调模型!
Datawhale AI冬令营(第一期) 垂类大模型构建 定制垂类大模型 = 优质数据集 + 开源大模型 整理者:博客园-岁月月宝贝!!! 姓名:HeYang 特别鸣谢Datawhale!!!:htt ...
- JavaScript 数组展平方法: flat() 和 flatMap()
从 ES2019 中开始引入了一种扁平化数组的新方法,可以展平任何深度的数组. flat flat() 方法创建一个新数组,其中所有子数组元素以递归方式连接到特定深度. 语法:array.flat(d ...