MDI窗体关闭问题解决一例

由于工作忙,很久没有来这里了,久违了。

背景:

MDI子窗体中的一个是导航窗体,该窗体定义了CLOSING事件处理:检测窗体的关闭标志是否允许,如果不允许则取消关闭操作,这样保证了导航窗体的不被关闭而永久存在。


问题:

当关闭MDI容器窗体的时候,因为其中一个子窗体的关闭事件被取消了,所以关闭动作失败,导致要关闭MDI主窗体只能通过调用Application的Exit方法来实现真正的关闭操作。

解决:
当关闭MDI子窗体的时候,由于导航窗体有关闭控制处理,可能会取消窗体的关闭操作,因此设想:在主窗体关闭的时候,设置导航窗体的关闭标志为允许关闭,这样主窗体就不会因为子窗体的关闭被取消而取消了。但实验结果是不可行:所有子窗体的CLOSING事件都在主窗体的CLOSING事件之前触发,当在主窗体进行可关闭标志的设置的时候,对主窗体已经是无效的了。感觉很沮丧,总不能让用户执行两次关闭操作吧?使用Application.Exit来处理,也感觉不理想,便采用对导航窗体的可关闭标志进行置位后再次调用关闭函数来实现。
经过跟踪处理,发现,主窗体和所有的子窗体共用同一个CLOSING事件参数(System.ComponentModel.CancelEventArgs),因此导致只要任何一个窗体(包括主窗体和子窗体)取消的关闭事件,那么整个关闭操作就失败。基于这个原因,在主窗体的CLOSING事件里面,设置CANCEL=false轻松解决问题(因为主窗体的CLOSING事件永远都是最后一个被触发)。
以上解决方案又会带来一个漏洞:除了导航窗口外,如果有其它窗体确实需要取消关闭操作将会导致失败。对于这个问题,可以采用以下两个方案处理:
1——
在主窗体的CLOSING处理中,强制CANCEL标记复位,然后执行每个子窗体是否确实允许关闭的检测再来设置CANCEL标志。
这个方案不好的地方是主窗体必须知道子窗体是否定义了指定的函数,导致主窗体对子窗体的实现类型存在依赖

2——
基于方案1中存在的问题,考虑:各子窗体是否真的可以被关闭的标志置于Tag属性中,这样,子窗体与主窗体之间只要达成这个协议就可以很好的解决这个问题。
相关代码:
子窗体Closing事件代码:

None.gif if  (CanClose)
ExpandedBlockStart.gifContractedBlock.gif
dot.gif {
InBlock.gif    
if(Tag == null)
ExpandedSubBlockStart.gifContractedSubBlock.gif    
dot.gif{
InBlock.gif        Tag 
= true;
ExpandedSubBlockEnd.gif    }

InBlock.gif    
else
ExpandedSubBlockStart.gifContractedSubBlock.gif    
dot.gif{
InBlock.gif        ArrayList arrTmp  
= new ArrayList();
InBlock.gif        arrTmp.Add(
true);
InBlock.gif        arrTmp.Add(Tag);
InBlock.gif        Tag 
= arrTmp;
ExpandedSubBlockEnd.gif    }

ExpandedBlockEnd.gif}

None.gif


主窗体Closing事件处理代码:

None.gif e.Cancel  =   false ;
None.gif
foreach (Form frmTmp  in   this .MDIChildren)
ExpandedBlockStart.gifContractedBlock.gif
dot.gif {
InBlock.gif    
if (frmTmp.Tag == null)
InBlock.gif        
continue;
InBlock.gif    
if(frmTmp.Tag is bool)
ExpandedSubBlockStart.gifContractedSubBlock.gif    
dot.gif{
InBlock.gif        
if ((bool)frmTmp.Tag))
ExpandedSubBlockStart.gifContractedSubBlock.gif        
dot.gif{
InBlock.gif            e.Cancel 
= true;
InBlock.gif            
break;
ExpandedSubBlockEnd.gif        }

InBlock.gif        frmTmp.Tag 
= null;
ExpandedSubBlockEnd.gif    }

InBlock.gif    
if(frmTmp.Tag is ArrayList)
ExpandedSubBlockStart.gifContractedSubBlock.gif    
dot.gif{
InBlock.gif        ArrayList arrTmp 
= frmTmp.Tag as ArrayList;
InBlock.gif        
if(arrTmp.Count != 2 || !(arrTmp[0is bool))
InBlock.gif            
continue;
InBlock.gif        frmTmp.Tag 
= arrTmp[1];
InBlock.gif        
if((bool)arrTmp(0))
ExpandedSubBlockStart.gifContractedSubBlock.gif        
dot.gif{
InBlock.gif            e.Cancel 
= true;
InBlock.gif            
break;
ExpandedSubBlockEnd.gif        }

ExpandedSubBlockEnd.gif    }

ExpandedBlockEnd.gif}

None.gif
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
我喜欢里面自动完成的功能,HOHO 本软件CnPlugin是Allround Automations公司PL/SQL Developer工具的插件,支持PL/SQL Developer 7.0以上版本。增加了PL/SQL Developer工具本身所没有的一些小功能,功能基本一些已有官方插件的整合,以方便Oracle编程开发。 1.5.400现有功能简要说明: 主菜单功能 所有主菜单可在PL/SQL中设置工具栏按钮,以方便调用 CnPlugin / Comment /&Commnet Lines 以“--”注释当前选中的代码 CnPlugin / Comment /&Uncommnet Lines 去除当前选中以“--”注释的代码 CnPlugin / &ReConnect 重连中断的数据库连接 CnPlugin / &ExPaste 对当前选中或剪贴板内空格式化为IN 字符串,如格式化字符串AA,BB,CC为('AA','BB',CC') CnPlugin / &ExCreate 建表时插入COMMENT的字段说明,如CREATE TABLE tt(ID NUMBER --编号);语句,除执行当前建表语句外,会自动生成comment on column TT.ID is '编号'注释语句 CnPlugin / Script / Load From MDB 以列表窗口形式读取已保存在Access数据库中的SQL语句 CnPlugin / Script / Save To MDB 保存当前SQL语句至Access数据库 CnPlugin / Script / Save As To MDB 另存为当前SQL语句至Access数据库 CnPlugin / Toggle Read Only 设置/取消设置当前SQL窗口为直读。 CnPlugin / Find All... 对当前窗口内空查找指定的字符串,列出全部匹配内容,支持正则表达式查找 CnPlugin / &Preferences CnPlugin插件属性设置窗口 CnPlugin / &About' CnPlugin关于窗口 右键菜单功能 Query data using alias 以字段注释字符作为字段名拼出查询SQL语句(选中表名出现) Open in new SQL Window 复制当前窗口选中的SQL语句到新窗口中(选中字符串是出现) Execute in new SQL Window 复制当前窗口选中的SQL语句到新窗口中并执行语句(选中字符串是出现) Generate Word Documentation 导出当前表结构内容至Word文档(选中表名出现) 无菜单功能 快捷键输入功能:如输入s空格,带出'select * from ',支持光标定位 登录时打开或执行指定SQL文件
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值