始终保持打开同一个子窗口以及关闭父窗口同时自动关闭所有子窗口

本文介绍了一种使用JavaScript在浏览器环境中实现类似WinForm多窗口管理的方法。通过window.open和自定义HashMap来跟踪和控制多个子窗口的打开状态,确保同一窗口只被打开一次,并能在主窗口关闭时同步关闭所有子窗口。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

需求如题,

原始需求来自今天优快云 asp.net 板块的一个求助贴:

None.gif 1 .点击一个可以打开新窗体的链接,如何实现如果窗体已打开,则将焦点转到已打开的窗体,否则打开新窗体。难点:如何判断窗体已打开,及将将打开的窗体Active?
None.gif
None.gif
2 .如何实现一个主窗体关闭时,将所有 打开的其他相关窗体一起关闭?
None.gif
None.gif
None.gif我们主管以前是做WinForm的,现在升级系统Asp.net做开发。但思维模式还是WinForm。提的这两个要求实难下手去做,请教各位是否有办法实现,若有请告之,谢谢!
None.gif
None.gifhttp://community.youkuaiyun.com/Expert/topic/
5587 / 5587936 .xml?temp = .7338983

虽然是有点变态,还硬是将他基本实现了,希望不会有太多潜在bug~

其实自己很早都有这种需求,只是之前都懒得去尝试,变样实现了,
至于父子窗口交互控制、互相调用方法、互相传值,地球人倒是实现了不少,

google + baidu 好像都没有完整的实例可供参考,只有自己实现

这里,我采取了 window.open ,还没有尝试 window.showModelessDialog,
对于 IE,来说后者可能更适合,更好交互控制

实现要点
1.  window.open 会返回新打开窗口的 window 对象
2. 实现一个模拟的简单 HashMap 存储子窗口的 window 对象
3. 每次 open 的时候,检索此 HashMap,确定子窗口是否已存在,
4. 若存在则直接切换焦点 (window.focus)
5. 若不存在,则 open 一个
6. 对于4,有可能子窗口已关闭,故采取了点技巧,先调用其 focus (其实可以任意方法),若出错,则也open 一个
7. 关闭 parent 的时候,遍历 HashMap,尝试关闭所有子窗口
8. 所有操作在父窗口实现
9. 整个实现原理其实很简单,只要需要熟悉js和dhtml,然后注意细节问题处理

目前   IE 6 sp1 测试通过,FF 由于不支持 window.focus 故不适合使用

对于 FF window.focus 问题参考:
http://hi.baidu.com/aolaii/blog/item/1bce87d6d9a1f62f06088b41.html
http://groups.google.com/group/mozilla.support.firefox/browse_thread/thread/470462a7876dd154/eae3d04ce24aa58e?lnk=st&q=focus+firefox+raise&rnum=1#eae3d04ce24aa58e

现在有点崇拜那句话了,"nothing is impossible!",当然前提是要合理的^_^

欢迎拍砖~


ContractedBlock.gif ExpandedBlockStart.gif
None.gif<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
None.gif
<html xmlns="http://www.w3.org/1999/xhtml" >
None.gif
<head>
None.gif    
<title>Parent window</title>
ExpandedBlockStart.gifContractedBlock.gif    
<script type="text/javascript">dot.gif    
ExpandedSubBlockStart.gifContractedSubBlock.gif    
function openWin() dot.gif{
InBlock.gif        
//debugger;
InBlock.gif
        var sltWins = document.getElementById("sltWins");
InBlock.gif        
var url = sltWins.value;
InBlock.gif        
var winName = url.replace('.', '_');
InBlock.gif        
var win;
InBlock.gif        win 
= winMap[winName];
ExpandedSubBlockStart.gifContractedSubBlock.gif        
try dot.gif{
InBlock.gif            win.focus();            
ExpandedSubBlockStart.gifContractedSubBlock.gif        }
catch(e) dot.gif{
InBlock.gif            
// alert(e.message);
InBlock.gif
            // we need to open a new window when the child window has not 
InBlock.gif
            // been opened or the child window has been close.
InBlock.gif
            // as to the later, you also can implements some method that notices the parent window
InBlock.gif
            // to remove the child window from our winMap object when it is closing.
InBlock.gif
            // but it's a piece of hard work, i think so, because you must 
InBlock.gif
            // add the notice codes to all the child windows
InBlock.gif
            //             
InBlock.gif
            win = window.open(url, winName, "top=100,left=100,width=400,height=300"); 
InBlock.gif            winMap[winName] 
= win;
InBlock.gif            
//
ExpandedSubBlockStart.gifContractedSubBlock.gif
            if(!win) dot.gif
InBlock.gif                alert(
"Sorry, fail to open the window.Some unexpected error occurs."); 
ExpandedSubBlockEnd.gif            }

ExpandedSubBlockStart.gifContractedSubBlock.gif            
else dot.gif{
InBlock.gif                    
// i try to bind a callback function to the child window's unload event
InBlock.gif
                    // unfortunately, it seems not to work.
InBlock.gif//
                win.onunload = function() { 
InBlock.gif//
                    try {
InBlock.gif//
                        alert(opener.winMap[winName]);
InBlock.gif//
                        opener.winMap[winName] = null; 
InBlock.gif//
                        alert(opener.winMap[winName]);
InBlock.gif//
                    } catch(e) {
InBlock.gif//
                        // alert(e.message);
InBlock.gif//
                    }
InBlock.gif//
                };
InBlock.gif
                win.focus();
ExpandedSubBlockEnd.gif            }

ExpandedSubBlockEnd.gif        }
        
ExpandedSubBlockEnd.gif    }

ExpandedBlockEnd.gif    
</script>
ExpandedBlockStart.gifContractedBlock.gif    
<script type="text/javascript">dot.gif
InBlock.gif    
// stores the opened window object
InBlock.gif
    var winMap = new Object();
InBlock.gif    
//winMap["TestedKey"] = "TestedValue";
ExpandedSubBlockStart.gifContractedSubBlock.gif
    window.onunload = function() dot.gif{
InBlock.gif        
// try to close all child windows.
ExpandedSubBlockStart.gifContractedSubBlock.gif
        for(var propName in winMap) dot.gif{
ExpandedSubBlockStart.gifContractedSubBlock.gif            
try dot.gif{                
InBlock.gif                winMap[propName].close(); 
ExpandedSubBlockStart.gifContractedSubBlock.gif            }
catch(e) dot.gif{
InBlock.gif                
//alert(e.message);
ExpandedSubBlockEnd.gif
            }
           
ExpandedSubBlockEnd.gif        }

ExpandedSubBlockEnd.gif    }

ExpandedBlockEnd.gif    
</script>
None.gif
</head>
None.gif
<body>
None.gif    
<h3>Maintaining the Parent window and Multi Child windows as in WinForm</h3>  
None.gif    
<h4>funcions:</h4>  
None.gif    
<ol>
None.gif        
<li>Open the same child window once.</li>
None.gif        
<li>Close all the child windows when the parent window is closing.</li>    
None.gif    
</ol>
None.gif    Child window:
None.gif    
<select id="sltWins">
None.gif        
<option selected="selected" value="c1.htm">#1</option>
None.gif        
<option value="c2.htm">#2</option>
None.gif    
</select>
None.gif    
<br />
None.gif    
<input id="btnOpen" type="button" value="Open the selected window" onclick="openWin()" />
None.gif
None.gif
</body>
None.gif
</html>
None.gif

下载

<think>好的,用户的问题是关于如何通过编程实现避免多次打开相同窗口的功能。我需要先理解用户的需求,然后根据提供的引用内容来寻找合适的解决方案。 首先,用户提到“防止重复打开同一个窗口”,也就是说在应用程序中,当用户尝试打开某个窗口时,如果该窗口已经存在并且可能还在运行,系统应该检测到这一点,而不是创建一个新的实例,而是将焦点切换到现有的窗口上。这样可以避免资源浪费和用户界面混乱。 根据用户提供的引用内容,特别是引用[1],里面提到了三种方法来实现单例模式或检查窗体是否已打开。方法一使用单例模式,确保一个类只有一个实例,并提供一个全局访问点。方法二遍历Application.OpenForms来判断窗体是否已经打开。方法三则是通过遍历this.MdiChildren(在MDI父窗体中)来判断窗体是否存在。这些方法都可以用来防止重复打开同一个窗口。 接下来,我需要考虑用户可能的开发环境。引用[1]中的方法二和方法三看起来像是C# WinForms的代码,因为提到了Application.OpenForms和MDI窗口。因此,假设用户在使用C# WinForms进行开发,我需要针对这个环境来提供解决方案。 首先,单例模式是一种设计模式,适用于确保一个类只有一个实例。在WinForms中,如果窗口被设计为单例,那么每次尝试打开时都会返回同一个实例。但需要注意线程安全和窗体关闭后的处理,因为单例一旦创建,可能不会被销毁,即使窗体被关闭,实例仍然存在,这可能导致问题。因此,需要确保在窗体关闭时正确释放资源,或者重新初始化实例。 方法二和方法三则是通过遍历当前打开的窗体列表或MDI窗口列表来检查是否存在目标窗体。这种方法更动态,每次打开窗体时进行检查,如果存在则激活,否则创建新实例。这可能更灵活,尤其是当窗体可能被用户关闭后需要重新打开的情况。 接下来需要详细说明每种方法的实现步骤,并给出代码示例。例如,单例模式需要将构造函数设为私有,提供一个静态实例,并在访问时检查是否已存在。对于方法二,遍历Application.OpenForms集合,检查窗体名称或类型,然后激活或创建。方法三适用于MDI应用程序,遍历父窗体的MdiChildren集合,同样检查类型或名称。 还需要考虑一些细节,比如窗体的Name属性是否正确设置,或者在MDI环境中父窗体的正确引用。此外,可能需要处理窗体被关闭后的情况,比如在方法二中,如果窗体已经被关闭,但实例仍在内存中,可能需要特别处理,但WinForms通常会在窗体关闭后将其从OpenForms列表中移除,所以可能不需要担心这个问题。 用户可能还关心这些方法的优缺点。例如,单例模式确保全局唯一实例,但可能不适合需要多个实例的场景。而遍历窗体列表的方法更灵活,但每次都需要检查,可能稍微影响性能,不过在实际应用中影响不大。 最后,根据引用内容,需要确保在回答中正确引用来源,比如引用[1]中的方法。同时,用户可能需要知道如何选择不同的方法,根据他们的具体应用场景,比如是否是MDI应用程序,或者是否需要严格的单例控制。 总结,我需要分步骤解释三种方法,提供代码示例,并讨论它们的适用场景和注意事项,帮助用户选择最适合他们需求的方法。</think>在C# WinForms中,防止重复打开窗口可以通过以下三种方法实现,根据引用[1]的描述并结合实际开发场景,具体实现步骤如下: ### 方法一:单例模式实现 ```csharp public class ChildForm : Form { private static ChildForm instance; // 私有静态成员 private ChildForm() // 私有构造函数 { InitializeComponent(); this.FormClosed += (s, e) => { instance = null; }; // 关闭时释放实例 } public static ChildForm GetInstance() // 公有静态方法 { return instance ??= new ChildForm(); // C# 8.0空合并赋值运算符 } } ``` **调用方式**:`ChildForm.GetInstance().Show();` **特点**:通过私有构造函数限制实例化次数,窗体关闭自动释放实例,避免内存泄漏[^1]。 ### 方法二:遍历Application.OpenForms ```csharp public void OpenChildForm() { foreach (Form form in Application.OpenForms) { if (form is ChildForm) // 按类型判断 { form.BringToFront(); // 已存在则前置 return; } } new ChildForm().Show(); // 不存在则新建 } ``` **注意**:需要确保窗体的`Name`属性唯一,或通过`Tag`属性添加标识符辅助判断。 ### 方法三:MDI容器环境检测 ```csharp public void OpenMdiChild() { foreach (Form childForm in this.MdiChildren) // 遍历MDI窗口集合 { if (childForm.GetType() == typeof(ChildForm)) { childForm.Activate(); // 激活已有窗口 return; } } new ChildForm { MdiParent = this }.Show(); // 创建新窗口 } ``` **适用场景**:专为多文档界面(MDI)应用程序设计,要求父窗体设置`IsMdiContainer = true`。 ### 性能对比 | 方法 | 内存占用 | 适用范围 | 窗体独立性 | |-----------|------|------------|-------| | 单例模式 | 低 | 全局唯一实例 | 非MDI | | OpenForms | 中 | 普通WinForms | 支持多实例 | | MDIChildren | 高 | MDI容器环境 | 仅限MDI | ### 扩展应用 1. **动态传参处理**:在窗体激活时,可通过`Tag`属性传递新参数并刷新界面 2. **异步加载优化**:结合`BeginInvoke`实现非阻塞窗体加载 3. **生命周期管理**:通过`FormClosing`事件记录窗体状态
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值