WinForm vs WPF .Close() 事件

Posted

技术标签:

【中文标题】WinForm vs WPF .Close() 事件【英文标题】:WinForm vs WPF .Close() event 【发布时间】:2014-01-19 08:37:30 【问题描述】:

WinForm

public Form1()

    Form2 obj = new Form2();
    obj.show(); //shows form2
    this.Close(); //exception crash: because constructor has not yet called `new Form1.show()`

Winform

    'this.close()' 将通过异常和崩溃(无法处理未初始化的对象) 如果我不在 Form1 中调用 .close,并且我关闭(X)Form1,Form2 也会被关闭,因为它是 Form1 中的一个实例

WPF,相同的代码:

    'this.close()' 不会通过异常 如果 Form1 关闭,Form2 将作为 MainWindow 保持打开状态。

Why is the Difference?

(编辑) 我知道在 Winform 中我无法在构造函数中关闭相同的表单,因为它尚未创建,但 how is WPF differ with it in constructor call?

如果我想让所有子窗口在父窗口关闭时关闭,WinForm 方式?

【问题讨论】:

在 WinForms 中,考虑使用 InitializeControls/FormLoaded 而不是在构造函数中创建控件(尤其是尝试关闭同一个表单)。 在 WPF 中,您正在关闭 Window 或 UserControl? 你见过***.com/questions/3067901/… @RohitVats 在 WPF 中我正在关闭窗口 @grantnz 正如我所提到的,我已经知道我无法在构造函数中关闭表单,因为它尚未在 WinForm 中创建,我的问题是它与 WPF 有何不同,关闭时不会出错并且不是父级在构造函数中创建的窗口。 【参考方案1】:

不同之处在于每个类的 Close 方法是如何实现的。尽管 System.Windows.Forms.Form 和 System.Windows.Window 在功能和外观上有相似之处,但它们是两个完全不同的类,它们围绕两种不同的架构构建。

System.Windows.Forms.Form 自 .NET 1.0 以来就已经存在,并且主要是围绕原生 precudral(即非面向对象的)Windows UI 库的一个轻薄、更易于使用的包装器。

System.Windows.Window 是 WPF 的一部分,它是在 .NET 3.0 中引入的,它试图在 CLI 之上构建现代 UI 框架(而不是简单地包装旧的 Windows UI 库)。因此,System.Windows.Window 的实现可能与 System.Windows.Forms.Form 的实现完全不同。此外,尽管这些类上可用的操作可能表面上相似,但它们在语义上可能并不相同。从这个意义上说,Form.Close 和 Window.Close 的含义不一定完全一样。

现在,在这种特殊情况下,根据文档 (http://msdn.microsoft.com/en-us/library/system.windows.forms.form.close(v=vs.110).aspx),您会收到此异常,因为“在创建句柄时表单已关闭。”如果您稍微解压缩此语句,这意味着您在创建窗体的窗口句柄 (HWND) 之前调用了 Close 方法。这实际上与您在构造函数中关闭窗口的事实无关:Form 类的构造函数此时已经完成。 .NET 中的 Form 对象表示 Windows 操作系统中的本机窗口,由窗口句柄(或 HWND,它是 C/C++ 中使用的类型名称)标识。但是,因为创建窗口句柄是一个昂贵的过程,所以 Form 对象在真正需要它之前不会真正创建句柄。因此,在您调用 Form.Show、Form.HWND 或其他一些强制创建它的方法之前,表单对象的窗口句柄并不存在。如果您在 this.Close() 之前调用了 this.Show(),则不会抛出异常。

为什么在 System.Windows.Window 中不是这种情况?我的猜测是 System.Windows.Window 中的 Close 方法有点“聪明”,如果它还不存在,它会简单地跳过处理句柄的步骤。或者,可能是急切地创建了窗口句柄,这与 Forms 实现不同。

这种差异是否完全是故意的很难说。目前尚不清楚“关闭”一个从未显示过的窗口是否有意义,以及尝试这样做是否会导致异常。它是一种设计选择。微软程序员现在可能更喜欢 System.Windows.Window.Close 的语义,而不是不太宽容的 System.Windows.Forms.Close,但做出这样的改变不会向后兼容。或者,可能没有人真正注意到或考虑过这种差异。

【讨论】:

+1 感谢您提供详细信息。我明白了。我对来自 WinForm 背景感到困惑,但真正的问题仍然存在。在 WPF 中,如果我关闭 Form1,是否应该关闭 Form2,因为它的实例在 Form1 内。 Window 没有 .Dispose()。 实际上,我真的不确定您要完成什么。但是,简短的回答是否定的。仅仅因为 Form2 是在 Form1 的构造函数中创建的,并不意味着 Form2 在 Form1 中。 Form2 是它自己的独立的 Window 实例。您可以持有对 Form2 的引用,然后重写 Form1 的 Close 方法以显式地关闭 Form2.Close。或者,如果您尝试关闭程序,您可以调用 Application.Current.Shutdown。如果您发布一个新问题并解释您实际尝试做的事情,这可能是最好的。 感谢您的回复,实际上从您的信息和 Bsienn 的回答中,我了解了我遇到的问题。实际上,当我关闭 Window1 时,我希望它会关闭 Window2 并退出程序。但在 WPF 中并非如此。 我怀疑当它在 Windows 窗体中以这种方式工作时,它实际上并不是“设计使然”。第二个窗口是否因为抛出异常而导致程序崩溃而关闭?如果是这样,那么有更清洁的方法来完成这项任务。异常并不是关闭应用程序的一种方式。相反,当抛出未处理的异常时程序会关​​闭,因为这被认为比让程序运行在可能损坏的状态下更安全。实际上,您可以覆盖该行为并让程序在抛出未处理的异常后继续运行。【参考方案2】:

在 WPF 中,您不会手动处理 WPF 对象,当没有更多对它们的引用时,它们会被垃圾回收。

由于您的 Form1 引用了 Form2,您的 Form1 将在后台保持活动状态,将表单隐藏在 .close() 上,直到您也关闭 Form2。

您可以在 Form1 的关闭事件中销毁所有对象,或者您可以强制您的应用程序关闭,除非您处理未保存的数据,否则这不是一个好主意。

这是非常全面的信息How to exit a WPF app programmatically?

【讨论】:

+1 感谢您的回复,我现在明白了这个问题。因为您的答案是正确的,但很抱歉不能接受您的回答,因为我只能 1. 我在一个主题中提出 2 个问题的错误。

以上是关于WinForm vs WPF .Close() 事件的主要内容,如果未能解决你的问题,请参考以下文章

Winform VS WPF?

VS2010在winform中怎么转到html

C#中winform中有啥办法区分Close()和点击窗体右上角关闭按钮来关闭窗体

winform VS2010视图设计器更新的问题

winform 别人部署后的项目怎样再用vs2010 打开?

vs winform项目如何改成4.0,创建时用的是4.5的,现在需要改成4.0的