2012-03-13 52 views
3

我有一個Windows窗體打開另一個窗體。在輔助形式中,它以異步方式啓動任務。如果用戶啓動的任務,然後取消它,並迅速關閉形式,形式爲設置,並設置當任務被取消,我仍然獲得了MessageBox.Show發生任務保持表單實例是否打開?

public class MyMainForm : Form 
{ 
    public void OpenChildForm() 
    { 
    MyChildForm form = new MyChildForm(); 
    form.ShowDialog(); 
    form.Dispose(); 
    form = null; 
    } 
} 

public class MyChildForm : Form 
{ 

    private CancellationTokenSource MyTokensource; 
    private Task task; 


    public void StartTask() 
    { 
    MyTokensource = new CancellationTokenSource(); 
    task = Task.Factory.StartNew(() => MyMethod(MyTokensource.Token), MyTokensource.Token); 
    } 

    public void MyMethod(CancellationToken token) 
    { 
     var result = StaticClass.DoSomethingLengthy(token); //The cancel make take a couple of seconds to return here 
     if (result == Cancelled) 
     { 
     MessageBox.Show("Cancelled"); 
     UpdateLabel("Cancelled") 
     } 
    } 

    public void ButtonClose_Click() 
    { 
    if (task != null && !task.IsCompleted) 
    { 
     MyTokensource.Cancel(); 
    } 
    this.Close(); 
    } 
} 

回答

2

形式佈置並設置當任務被取消,我仍然獲得了MessageBox.Show發生

設置變量是表單的引用回來然而空爲空,甚至在窗體上調用Dispose(),實際上並沒有破壞的形式。該任務仍在執行,直至取消(CancellationTokenSource被設計爲取消合作模式)。

因此,您需要明確處理任務被取消時發生的代碼路徑。這可能是因爲檢查,看看是否你已經設置,即簡單:

if (this.IsDisposed) 
    return; // Just break out if we canceled and shut down 

// Your other code.... 
if (result == Cancelled) 
    MessageBox.Show("Cancelled"); 
+0

這工作雖然我不明白你爲什麼說它沒有被摧毀的事件,雖然我打電話處置。我猜是因爲GC沒有踢進去! – Jon 2012-03-13 16:22:37

+0

@Jon Dispose **對內存(不一定)**或任何管理對象沒有直接影響。這只不過是一種方法,(按慣例)用於釋放本地資源。它對由CLR分配和管理的內存或對象沒有影響。請參閱:http:// reedcopsey。com/series/idisposable /當然,所討論的「資源」可能是內存,但也可能是其他任何東西,或者甚至沒有任何東西。 – 2012-03-13 16:26:30

2

這使得回來然而空感。 Task不是異步執行的,它的執行生命週期並不與Form的生命週期有關。你只需要添加一個明確的檢查,以確保你不顯示MessageBox如果Form已經被/已被處置:

if(result == Cancelled 
      && 
    !(this.Disposing 
      || 
    this.IsDisposed)) 
{ 
    MessageBox.Show("Cancelled"); 
} 
+0

但是,爲什麼不像UpdateLabel這樣的事情會因爲我認爲標籤不存在等原因而倒塌。 – Jon 2012-03-13 16:06:11

+1

不應該這樣讀取&&!(this.Disposing || this.IsDisposed)'? – 2012-03-13 16:06:13

+0

@ThorstenDittmar對,忘了我不是。更新樣本。 – 2012-03-13 16:56:19

0

形式的情況下仍然存在,即使窗口可能不可見。爲確保在表單關閉後未顯示MessageBox,請將事件添加到OnClosing,並將成員變量m_formClosed設置爲true。僅在成員變量爲false時才顯示消息。

if (result == Cancelled && !m_formClosed) 
    MessageBox.Show("Cancelled"); 
0

的GC可能沒有收集的形式,儘管你叫Dispose()並設置爲null引用。這是正常的,因爲GC是非確定性的。

由於道路IDisposable實現,你可以檢查表上的IsDisposedIsDisposing屬性,看看是否Dispose()方法已經被調用或者是在正在運行的進程。

1

另一件需要注意的事情:確保你不是多次撥打StartTask()

如果是這樣,您最終會得到多個異步任務,並且有多個CancellationTokenSource實例(其中只有一個仍由表單引用)。