关于Form.Close跟Form.Dispose
我们在Winform开发的时候,使用From.Show来显示窗口,使用Form.Close来关闭窗口。熟悉Winform开发的想必对这些非常熟悉。但是Form类型实现了IDisposable接口,那我们是否需要每次关闭窗口后都去调用Dispose呢?对于这个问题我们可以查看一下Form的源码。
Form.Close
public void Close()
{
if (this.GetState(262144))
throw new InvalidOperationException(SR.GetString("ClosingWhileCreatingHandle", new object[1]
{
(object) "Close"
}));
else if (this.IsHandleCreated)
{
this.closeReason = CloseReason.UserClosing;
this.SendMessage(16, 0, 0);
}
else
base.Dispose();
}
很明显这个方法有3个分支。第一个分支是关闭出现异常的情况,第二个分支是句柄已经创建的时候执行,很明显第三个分支的时候直接调用了基类的Dispose方法。大部分时候窗口调用Close时句柄肯定是被创建了,那就会进入第二个分支。很明显第二个分支没有调用Dispose,那是不是真的呢?继续跟进去。
SendMessage
internal IntPtr SendMessage(int msg, int wparam, int lparam)
{
return UnsafeNativeMethods.SendMessage(new HandleRef((object) this, this.Handle), msg, wparam, lparam);
}
调了一个静态方法继续进去
[DllImport("user32.dll", CharSet = CharSet.Auto)]
public static IntPtr SendMessage(HandleRef hWnd, int msg, int wParam, int lParam);
明白了吧。SendMessage其实是调用了user32.dll的API,向指定的窗口发送消息。这里就是向自己发送一个消息,注意msg=16哦。既然有发送消息的,那肯定得有拦截消息的方法啊。(这里多扯一句,.NET Winform使用了事件驱动机制,事件机制其实也是封装了消息机制。)
WndProc
protected override void WndProc(ref Message m)
{
switch (m.Msg)
{
case 529:
this.WmEnterMenuLoop(ref m);
break;
case 530:
this.WmExitMenuLoop(ref m);
break;
case 533:
base.WndProc(ref m);
if (!this.CaptureInternal || Control.MouseButtons != MouseButtons.None)
break;
this.CaptureInternal = false;
break;
case 546:
this.WmMdiActivate(ref m);
break;
case 561:
this.WmEnterSizeMove(ref m);
this.DefWndProc(ref m);
break;
case 562:
this.WmExitSizeMove(ref m);
this.DefWndProc(ref m);
break;
case 288:
this.WmMenuChar(ref m);
break;
case 293:
this.WmUnInitMenuPopup(ref m);
break;
case 274:
this.WmSysCommand(ref m);
break;
case 279:
this.WmInitMenuPopup(ref m);
break;
case 167:
case 171:
case 161:
case 164:
this.WmNcButtonDown(ref m);
break;
case 71:
this.WmWindowPosChanged(ref m);
break;
case 130:
this.WmNCDestroy(ref m);
break;
case 132:
this.WmNCHitTest(ref m);
break;
case 134:
if (this.IsRestrictedWindow)
this.BeginInvoke((Delegate) new MethodInvoker(this.RestrictedProcessNcActivate));
base.WndProc(ref m);
break;
case 16:
if (this.CloseReason == CloseReason.None)
this.CloseReason = CloseReason.TaskManagerClosing;
this.WmClose(ref m);
break;
case 17:
case 22:
this.CloseReason = CloseReason.WindowsShutDown;
this.WmClose(ref m);
break;
case 20:
this.WmEraseBkgnd(ref m);
break;
case 24:
this.WmShowWindow(ref m);
break;
case 36:
this.WmGetMinMaxInfo(ref m);
break;
case 1:
this.WmCreate(ref m);
break;
case 5:
this.WmSize(ref m);
break;
case 6:
this.WmActivate(ref m);
break;
default:
base.WndProc(ref m);
break;
}
}
.csharpcode, .csharpcode pre
{
font-size: small;
color: black;
font-family: consolas, "Courier New", courier, monospace;
background-color: #ffffff;
/*white-space: pre;*/
}
.csharpcode pre { margin: 0em; }
.csharpcode .rem { color: #008000; }
.csharpcode .kwrd { color: #0000ff; }
.csharpcode .str { color: #006080; }
.csharpcode .op { color: #0000c0; }
.csharpcode .preproc { color: #cc6633; }
.csharpcode .asp { background-color: #ffff00; }
.csharpcode .html { color: #800000; }
.csharpcode .attr { color: #ff0000; }
.csharpcode .alt
{
background-color: #f4f4f4;
width: 100%;
margin: 0em;
}
.csharpcode .lnum { color: #606060; }
WndProc就是用来拦截窗口消息的。看一下代码,Form重写了这个方法,一个很简单的switch。Case 16调用了 WmClose方法,继续跟进去。
WmClose
private void WmClose(ref Message m)
{
FormClosingEventArgs e1 = new FormClosingEventArgs(this.CloseReason, false);
if (m.Msg != 22)
{
if (this.Modal)
{
if (this.dialogResult == DialogResult.None)
this.dialogResult = DialogResult.Cancel;
this.CalledClosing = false;
e1.Cancel = !this.CheckCloseDialog(true);
}
else
{
e1.Cancel = !this.Validate(true);
if (this.IsMdiContainer)
{
FormClosingEventArgs e2 = new FormClosingEventArgs(CloseReason.MdiFormClosing, e1.Cancel);
foreach (Form form in this.MdiChildren)
{
if (form.IsHandleCreated)
{
form.OnClosing((CancelEventArgs) e2);
form.OnFormClosing(e2);
if (e2.Cancel)
{
e1.Cancel = true;
break;
}
}
}
}
Form[] ownedForms = this.OwnedForms;
for (int index = this.Properties.GetInteger(Form.PropOwnedFormsCount) - 1; index >= 0; --index)
{
FormClosingEventArgs e2 = new FormClosingEventArgs(CloseReason.FormOwnerClosing, e1.Cancel);
if (ownedForms[index] != null)
{
ownedForms[index].OnFormClosing(e2);
if (e2.Cancel)
{
e1.Cancel = true;
break;
}
}
}
this.OnClosing((CancelEventArgs) e1);
this.OnFormClosing(e1);
}
if (m.Msg == 17)
m.Result = (IntPtr) (e1.Cancel ? 0 : 1);
if (this.Modal)
return;
}
else
e1.Cancel = m.WParam == IntPtr.Zero;
if (m.Msg == 17 || e1.Cancel)
return;
this.IsClosing = true;
if (this.IsMdiContainer)
{
FormClosedEventArgs e2 = new FormClosedEventArgs(CloseReason.MdiFormClosing);
foreach (Form form in this.MdiChildren)
{
if (form.IsHandleCreated)
{
form.OnClosed((EventArgs) e2);
form.OnFormClosed(e2);
}
}
}
Form[] ownedForms1 = this.OwnedForms;
for (int index = this.Properties.GetInteger(Form.PropOwnedFormsCount) - 1; index >= 0; --index)
{
FormClosedEventArgs e2 = new FormClosedEventArgs(CloseReason.FormOwnerClosing);
if (ownedForms1[index] != null)
{
ownedForms1[index].OnClosed((EventArgs) e2);
ownedForms1[index].OnFormClosed(e2);
}
}
FormClosedEventArgs e3 = new FormClosedEventArgs(this.CloseReason);
this.OnClosed((EventArgs) e3);
this.OnFormClosed(e3);
base.Dispose();
}
WmClose这个方法略有点复杂,主要是用来出发OnCloseing,OnClosed等事件。看看最后,它终于调用了base.Dispose()。看来Close方法确实会自动调用Dispose。是吗,不要高兴的太早。仔细看看前面的代码,if (this.Modal) return; 看到没,当窗口是模态的时候,方法直接return了。
总结
到这里就差不多了。所以当我们使用ShowDialog来显示窗体的时候,当你关闭的时候,最好手动Dispose一下。为什么是最好呢,因为其实在GC回收垃圾的时候还是会调用窗体的Dispose的,因为在Form的基类的终结器里面有调用Dispose(false);
~Component()
{
this.Dispose(false);
}
.csharpcode, .csharpcode pre
{
font-size: small;
color: black;
font-family: consolas, "Courier New", courier, monospace;
background-color: #ffffff;
/*white-space: pre;*/
}
.csharpcode pre { margin: 0em; }
.csharpcode .rem { color: #008000; }
.csharpcode .kwrd { color: #0000ff; }
.csharpcode .str { color: #006080; }
.csharpcode .op { color: #0000c0; }
.csharpcode .preproc { color: #cc6633; }
.csharpcode .asp { background-color: #ffff00; }
.csharpcode .html { color: #800000; }
.csharpcode .attr { color: #ff0000; }
.csharpcode .alt
{
background-color: #f4f4f4;
width: 100%;
margin: 0em;
}
.csharpcode .lnum { color: #606060; }
其实在MSDN上微软就对这有说明,顺便吐槽一下中文MSDN的翻译,实在是太烂了。

有2种情况下需要手工调用Dispose:
1. 窗口是MDI的一部分且是不可见的
2.模态的时候
第二种情况就是现在说的,但是第一种情况我测试了下,没有复现出来,MDI里面的子窗口调用Close的时候跟正常一样,每次都会自动Dispose。试了很久还是一样的结果,求高人指定吧。
.csharpcode, .csharpcode pre
{
font-size: small;
color: black;
font-family: consolas, "Courier New", courier, monospace;
background-color: #ffffff;
/*white-space: pre;*/
}
.csharpcode pre { margin: 0em; }
.csharpcode .rem { color: #008000; }
.csharpcode .kwrd { color: #0000ff; }
.csharpcode .str { color: #006080; }
.csharpcode .op { color: #0000c0; }
.csharpcode .preproc { color: #cc6633; }
.csharpcode .asp { background-color: #ffff00; }
.csharpcode .html { color: #800000; }
.csharpcode .attr { color: #ff0000; }
.csharpcode .alt
{
background-color: #f4f4f4;
width: 100%;
margin: 0em;
}
.csharpcode .lnum { color: #606060; }
.csharpcode, .csharpcode pre
{
font-size: small;
color: black;
font-family: consolas, "Courier New", courier, monospace;
background-color: #ffffff;
/*white-space: pre;*/
}
.csharpcode pre { margin: 0em; }
.csharpcode .rem { color: #008000; }
.csharpcode .kwrd { color: #0000ff; }
.csharpcode .str { color: #006080; }
.csharpcode .op { color: #0000c0; }
.csharpcode .preproc { color: #cc6633; }
.csharpcode .asp { background-color: #ffff00; }
.csharpcode .html { color: #800000; }
.csharpcode .attr { color: #ff0000; }
.csharpcode .alt
{
background-color: #f4f4f4;
width: 100%;
margin: 0em;
}
.csharpcode .lnum { color: #606060; }
关于Form.Close跟Form.Dispose的更多相关文章
- Form.Close跟Form.Dispose
关于Form.Close跟Form.Dispose 我们在Winform开发的时候,使用From.Show来显示窗口,使用Form.Close来关闭窗口.熟悉Winform开发的想必对这些非常熟悉 ...
- 使用Form Builder创建Form具体步骤
使用Oracle Form Builder创建Form具体步骤 (Data Source为Table) 说明:当Block使用的Data Source为Table时,Form会自动Insert,Upd ...
- 知道Form.Show()和Form.ShowDialog()的区别吗
博客搬到了fresky.github.io - Dawei XU,请各位看官挪步.最新的一篇是:知道Form.Show()和Form.ShowDialog()的区别吗.
- form.Show()和form.ShowDialog()的区别、新建一个form和MessageBox.Show()的常见用法
一:form.Show()和form.ShowDialog()的区别 a. 任何窗体(派生于基类Form的类),都可以以两种方式进行显示. //非模式窗体From qform=new Form();q ...
- $(#form :input)与$(#form input)的区别
相信大家都很奇怪这两者的区别 我从两个方面简单介绍下 1. $("form :input") 返回form中的所有表单对象,包括textarea.select.button等 ...
- day75 form 组件(对form表单进行输入值校验的一种方式)
我们的组件是什么呢 select distinct(id,title,price) from book ORM: model.py class Book(): title=model.CharFiel ...
- {Django基础十之Form和ModelForm组件}一 Form介绍 二 Form常用字段和插件 三 From所有内置字段 四 字段校验 五 Hook钩子方法 六 进阶补充 七 ModelForm
Django基础十之Form和ModelForm组件 本节目录 一 Form介绍 二 Form常用字段和插件 三 From所有内置字段 四 字段校验 五 Hook钩子方法 六 进阶补充 七 Model ...
- http://www.vaikan.com/docs/jquery.form.plugin/jquery.form.plugin.html#getting-started
http://www.vaikan.com/docs/jquery.form.plugin/jquery.form.plugin.html#getting-started Jquery.Form 异步 ...
- ExtJs6解决添加和修改Form共用一个form的隐藏域的id的取消传值
问题重现:修改不会有问题,id会绑定之前的grid,有具体数字 添加有问题,因为id是空,传的是绑定值的话会显示“类名-1”,从int类型变成了string类型,后台会出错 这是EduQuestion ...
随机推荐
- https SSL主流数字证书都有哪些格式?
主流数字证书都有哪些格式? 一般来说,主流的Web服务软件,通常都基于两种基础密码库:OpenSSL和Java. Tomcat.Weblogic.JBoss等,使用Java提供的密码库.通过Java的 ...
- 《CSS 设计指南》学习笔记 一
本篇文章是对这几天看完 Charles Wyke-Smit 的 <CSS 设计指南> 后的一些学习笔记与心得,笔者好像是大一的时候开始接触网页设计,由于并不是计算机专业的,所以所有都是自己 ...
- 【Theano】安装Theano
http://blog.csdn.net/niuwei22007/article/details/47684673 http://blog.csdn.net/m624197265/article/de ...
- Navi.Soft30.产品.格式化.操作手册
1系统简介 1.1功能简述 在软件开发过程中,我们对字符串操作最多. 尤其是Web开发时,数据交换一般采用JSON或XML.本产品作用是格式化各种常用字符串,目前包括:Json,Xml,Html,Sq ...
- Quartz.Net 作业调度后台管理系统,基于Extjs
Quartz.Net是一个开源的.非常灵活的作业调度框架,具体使用方法和教程:http://www.cnblogs.com/shanyou/archive/2007/08/25/quartznettu ...
- 一致性哈希算法(consistent hashing)【转】
一致性哈希算法 来自:http://blog.csdn.net/cywosp/article/details/23397179 一致性哈希算法在1997年由麻省理工学院提出的一种分布式哈希 ...
- SecureCrt设置字符编码
SecureCrt设置字符编码,参考:http://www.2cto.com/os/201412/365535.html
- MassTransit RabbitMQ 参考文档
Autofac http://docs.autofac.org/en/latest/lifetime/startup.html RabbitMQ http://www.rabbitmq.com/dot ...
- Git回滚远程版本
摘要: 原创出处:www.bysocket.com 泥瓦匠BYSocket 希望转载,保留摘要,谢谢! “房子是租的 但生活不是” 1.故事的开始 远程master分支下代码被不小心提交了很多垃圾代码 ...
- 关于IT概念的一些思考
同事提及“软件工程.软件生命周期.项目管理.CMMI.IPD.RUP.UML及UML建模.面向对象分析与设计.需求分析.系统分析与设计……等等,它们到底是什么?它们之间有什么关系?” 下面是个人见 ...