如何判断已加载程序集中的RetailWindow是否已打开并避免重复打开
如何避免重复打开RetailWindow实例
嘿,这个场景我之前做类似的反射调用窗口时遇到过,分享两个靠谱的解决思路给你:
思路一:跟踪已创建的窗口实例
既然你是通过反射创建的RetailWindow实例,最直接的方式就是把这个实例存到全局变量里,每次点击按钮先检查它的状态:
首先声明一个全局变量来保存实例(根据你的项目结构调整作用域):
private object _retailWindowInstance;
然后修改按钮点击的代码:
// 先检查已有实例的状态 if (_retailWindowInstance != null) { Type retailWindowType = _retailWindowInstance.GetType(); // 获取WinForm窗口的核心状态属性 bool isDisposed = (bool)retailWindowType.GetProperty("IsDisposed").GetValue(_retailWindowInstance); bool isVisible = (bool)retailWindowType.GetProperty("Visible").GetValue(_retailWindowInstance); if (!isDisposed && isVisible) { // 窗口还活着,直接激活它(比重新打开更友好) retailWindowType.GetMethod("Activate").Invoke(_retailWindowInstance, null); return; } // 如果窗口已经被销毁,就把实例置空,后续重新创建 _retailWindowInstance = null; } // 实例不存在或已销毁,重新创建并打开 gAssembly = Assembly.LoadFrom(JLDBConnection.Properties.Settings.Default.DefaultString + @"\JLRetailTerminal.exe"); Type typ = gAssembly.GetExportedTypes().FirstOrDefault(s => s.Name == "RetailWindow"); if (typ != null) { _retailWindowInstance = Activator.CreateInstance(typ); typ.GetMethod("Show").Invoke(_retailWindowInstance, null); }
这个方法的好处是精准跟踪你自己创建的实例,不会误判其他同名窗口。
思路二:通过Windows API查找已打开的窗口
如果全局实例跟踪有风险(比如外部程序内部重启了窗口),可以用系统API枚举窗口,通过标题或类名判断:
先导入User32.dll的API:
using System.Runtime.InteropServices; [DllImport("user32.dll", SetLastError = true)] private static extern IntPtr FindWindow(string lpClassName, string lpWindowName); [DllImport("user32.dll")] private static extern bool SetForegroundWindow(IntPtr hWnd);
然后在按钮点击逻辑里:
// 先尝试查找窗口(替换成RetailWindow实际的标题) string targetWindowTitle = "零售终端窗口"; IntPtr windowHandle = FindWindow(null, targetWindowTitle); if (windowHandle != IntPtr.Zero) { // 找到窗口,激活它 SetForegroundWindow(windowHandle); return; } // 没找到就创建新窗口 gAssembly = Assembly.LoadFrom(JLDBConnection.Properties.Settings.Default.DefaultString + @"\JLRetailTerminal.exe"); Type typ = gAssembly.GetExportedTypes().FirstOrDefault(s => s.Name == "RetailWindow"); if (typ != null) { typ.GetMethod("Show").Invoke(Activator.CreateInstance(typ), null); }
如果不知道窗口标题,可以先创建一次实例,通过反射获取Title属性的值,之后用这个值来查找;如果窗口有唯一的类名,也可以把FindWindow的第一个参数设为类名,查找更精准。
额外注意点
- 如果
RetailWindow本身设计成了单例模式,那优先调用它的单例获取方法(比如GetInstance()),比自己跟踪实例更可靠。 - 多线程环境下要注意全局实例的线程安全,必要时加锁保护。
内容的提问来源于stack exchange,提问作者Ansel Cadien
相关产品推荐
相关产品推荐

