2010-08-31 86 views
11

我在C#中遇到了打開和關閉窗體的新問題。關閉後處理表格

我的問題是如何處理關閉後的窗體。

這裏是我的代碼:

的Program.cs:

static class Program 
{ 
    public static Timer timer; 

    [STAThread] 
    static void Main() 
    { 
     Application.EnableVisualStyles(); 
     Application.SetCompatibleTextRenderingDefault(false); 

     timer = new Timer { Interval = 1000}; 
     timer.Start(); 

     Application.Run(new Form1()); 
    } 
} 

Form1.cs中:

public partial class Form1 : Form 
{ 
    public Form1() 
    { 
     InitializeComponent(); 
    } 

    private void button1_Click(object sender, EventArgs e) 
    { 
     Form2 form = new Form2(); 
     form.ShowDialog(); 
     /// I've tried Dispose() method . but didn't work 
    } 
} 

Form2.cs:

public partial class Form2 : Form 
{ 
    public Form2() 
    { 
     InitializeComponent(); 
    } 

    private void Form2_Load(object sender, EventArgs e) 
    { 
     Program.timer.Tick += timer_Tick;  
     Close(); 
     // I've tried Dispose() method instead of Close() but didn't work 
    } 

    private int count = 0; 
    void timer_Tick(object sender, EventArgs e) 
    { 
     count++; 
     if (count == 5) MessageBox.Show(""); 
    } 
} 

編輯: 我的問題是:爲什麼消息框在5秒後顯示form2已關閉!

+1

爲什麼你想在垃圾收集器爲你做這件事之前處理這些表單?(假設沒有對錶單的引用)? – Lazarus 2010-08-31 14:52:09

+2

「它沒有工作」是什麼意思?是否引發異常?窗口不會消失嗎? @拉扎羅斯:好問題。 – DHN 2010-08-31 14:53:05

+0

[我需要在表單關閉後處理表單嗎?](https://stackoverflow.com/a/39501121/3110834) – 2017-12-04 19:03:44

回答

8

編輯:這個問題原來是關於處置。

首先,Dispose已經注意到垃圾收集。會發生以下情況:

  1. 你有一個全球性的Timer實例
  2. 創建窗口2
  3. 窗體2訂閱計時器
  4. 窗體2被關閉和/或設置
  5. 計時器事件觸發時,遞增計數器並顯示一個MessageBox
  6. Timer事件一直髮射,直到App關閉。

要理解的要點是關閉/處置只會改變窗體的狀態,他們不會(不能)'刪除'實例。所以(閉合)形式在那裏,反場仍然存在,事件發生。


OK,第1部分:

一個using() {}塊會更好,但這應該工作:

private void button1_Click(object sender, EventArgs e) 
    { 
     Form2 form = new Form2(); 
     form.ShowDialog(); 
     /// I've tried Dispose() method . but didn't work 
     form.Dispose(); // should work 
    } 

如果不是,請說明 「不工作」。


private void Form2_Load(object sender, EventArgs e) 
    { 
     Program.timer.Tick += timer_Tick;  
     Close(); 
     /// I've tried Dispose() method instead of Close() . but didn't work 
    } 

這是很奇怪,但我會認爲這是問題的人工代碼。

您的全球Program.Timer現在存儲對您的Form2實例的引用,並保持它不被收集。它不會阻止它被丟棄/關閉,所以你的計時器將繼續爲封閉形式開火,這通常會失敗並導致其他問題。

  1. 不這樣做(給Form2的它自己的定時器)
  2. 使用FormClosed事件退訂:Program.timer.Tick -= timer_Tick;
+2

+1對於建議使用語句,可能想給他一個例子。 – jsmith 2010-08-31 14:56:23

+0

親愛的亨克霍爾特曼,刪除計時器滴答事件是很好的解決方案,但我的問題是,爲什麼消息框顯示時,表單已處置? – Mironline 2010-08-31 15:10:28

+1

@Mironline:爲什麼不呢? Timer和MessageBox都不需要這種形式。嘗試在timer_Tick中設置一個Control屬性,你將會有一個異常。 – 2010-08-31 15:18:12

4

最簡單和最可靠的方法使用後處置廢棄Form是把使用塊內部的用法

using (Form2 form = new Form2()) { 
    form.ShowDialog(); 
} 

C#中的使用塊是一種基本上將以上代碼擴展到以下代碼的構造。

Form2 form; 
try { 
    form = new Form2(); 
    ... 
} finally { 
    if (form != null) { 
    form.Dispose(); 
    } 
} 
+0

以秒爲單位,form2必須在訪問之前初始化。如果它初始化永遠不等於null。我試過了,但消息框在5秒後顯示。 – Mironline 2010-08-31 15:18:12

+0

這隻適用於模態表單 – 2017-06-27 23:52:55

0

form.ShowDialog()將窗體顯示爲模態對話框。這意味着該呼叫在表單關閉之前不會返回。
請注意,單擊模式對話框上的關閉X不會關閉表單,它只是隱藏它。我猜測這就是讓你困惑的原因。 如果你想讓form1中的代碼繼續執行而不是阻塞,你應該調用Show()而不是ShowDialog()。點擊X時,非模態將關閉。

如果您確實需要阻塞模式對話框,則應該按照其他答案中所述使用使用塊包圍表單。
建立一個模式對話框時,通常會添加一個「OK」按鈕或類似的對象,並將該表單的AcceptButton屬性設置爲該按鈕,以允許用戶按下Enter鍵關閉該表單。同樣,您可以添加一個「取消」按鈕並設置CancelButton屬性來捕獲Esc鍵。
向兩個按鈕添加點擊處理程序,相應地設置表單的DialogResult屬性並調用Close()。

1

也許我正在閱讀的問題是錯誤的,但我想先生們需要知道,要關閉Form2.ShowDialog()打開的窗體(比如form2),您需要在Form2中設置Form2.DialogResult。只需設置該成員即可關閉表單並返回結果。

3

這是一個古老的問題,但它涉及到一些關於對象如何工作的有趣觀點。表單本質上是一個對象。同一類的所有對象共享相同的方法,但每個對象都有自己的數據。這是什麼意思?這意味着,關閉或處理對象不會從內存中釋放/刪除/刪除任何代碼。只有數據。所有關於一般物體的事情,不管語言如何。

現在,具體關於您的代碼。讓我們來看看Program.timer.Tick += timer_Tick;這行。這會在表單對象定時器對象中給出指向您的函數的指針。所以,現在,無論您對表單對象做什麼,定時器對象都將繼續調用該函數。計時器對象不關心您的表單,甚至不知道表單對象的存在。它只關心你傳遞給的指針的功能。就計時器對象而言,這個函數是一個獨立的函數。

Form.Close()是做什麼的? Form.Close()處理表單使用的資源,也就是標記表單的垃圾回收控件,除非表單使用ShowDialog顯示。在這種情況下,必須手動調用Dispose()。MSDN

不用說(也許並非如此不必要的),如果關閉/處置的形式清除從記憶功能,定時器對象有一個無效的指針,你的程序會崩潰 5秒。