2012-03-13 15 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は、フォームへの参照である変数を設定

起こり得るキャンセルされるから戻って来るときしかし、nullに設定されていますnullに、さらにはフォーム上で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

+0

@Jon Dispose **はメモリ(必然的に)**または管理オブジェクトに直接影響しません。それは、(慣例により)ネイティブリソースを解放するために使用される方法である。これは、CLRによって割り当てられ管理されるメモリやオブジェクトには影響しません。参照:http:// reedcopsey。com/series/idisposable /与えられた "リソース"はメモリである可能性がありますが、他のものでもよいし、何もできません。 –

2

起こり得るキャンセルされるから戻って来るときしかし、nullに設定されていますセンス。 Taskは非同期で実行されていません。その実行ライフタイムはFormの有効期間に関連付けられていません。あなたはちょうどあなたがすでに/破棄されているされているMessageBoxForm場合は表示されませんを確認するために、明示的なチェックを追加する必要があります。にもかかわらず、

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

しかし、私はラベルが存在しないなどの理由で、UpdateLabelが転倒してしまうのはなぜですか? – Jon

+1

これは '&&!(this.Disposing || this.IsDisposed)'ではありませんか? –

+0

@ThorstenDittmarうん、私は忘れてしまった。サンプルを更新しています。 –

0

フォームのインスタンスがまだそこにありますウィンドウが表示されないことがあります。フォームが閉じられた後にMessageBoxが表示されないようにするには、イベントをOnClosingに追加し、メンバー変数m_formClosedtrueに設定します。メンバー変数がfalseの場合にのみメッセージを表示します。

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

GCは、あなたがDispose()を呼び出し、ヌルへの参照を設定するにもかかわらず、フォームを収集していないことがあります。これはつまり、あなたが既に配置されているかどうかをチェックするのと同じくらい簡単かもしれません。 GCは非決定論的なので、これは正常です。ための方法IDisposable

が実装されている、あなたはDispose()メソッドがすでに呼び出されたり、実行中であるされているかどうかを確認するために、フォーム上のIsDisposedIsDisposingプロパティを確認することができます。

1

もう一度注意してください:StartTask()を複数回呼び出さないようにしてください。

もしそうなら、複数の非同期タスクと複数のインスタンスCancellationTokenSource(そのうちの1つだけが依然としてフォームによって参照されます)になります。

関連する問題