私は、完了したらUIを更新するバックグラウンドスレッドを持っています。私はできるだけ安全にしようとしていたので、私はDispositionされたGUIと呼んでいません。バックグラウンドスレッドからUIを更新する - GUIが削除されていないことをどのように知ることができますか?
void DoInBackground()
{
try
{
string result = ServerSideProcess();
* if (!IsDisposed && !Disposing)
* BeginInvoke(new StringDelegate(UpdateText), result);
}
catch (Exception ex)
{
* if (!IsDisposed && !Disposing)
* BeginInvoke(new VoidDelegate(UpdateFailed));
}
}
void UpdateText(string txt)
{
if (!IsDisposed && !Disposing)
textbox1.Text = txt;
}
void UpdateFailed()
{
if (!IsDisposed && !Disposing)
textbox1.Text = "failed to get data from server";
}
override Dispose(bool disposing)
{
if (disposing)
{
if (components != null)
components.Dispose();
}
base.Dispose(disposing);
}
私はGUIメソッドの内部に十分安全だと思います - 廃棄()私はUPDATETEXT(文字列)またはUpdateFailed(内てる間、呼び出されません)同じスレッドで、彼らの両方が実行されるため、だから、私はIsDisposingのチェックとそれ以降の実行が十分であると仮定している。しかし、(*)内のパーツがDispose()を間に合わないことをどのように知ることができますか?BeginInvokeは処理クラスで呼び出され、最終的にアプリケーションクラッシュが発生します。
Thread.Sleepの前と後にブレークポイントを入れ、BeginInvokeに達する前にDispose()dを得るようにコントロールから移動することで、(*)パーツ間にThread.Sleep(2000)を追加してテストしました。結果 - 私のアプリケーションがクラッシュしました。どのように私はこのランタイムは私にこの不運なコンテキスト切り替えのシナリオを与えてくれないことを知ることができますか?
'InvokeRequired'、' BeginInvoke'などの方法には不幸な欠点があります。あなたの 'Dispose'ルーチン内でロックガードされたフラグを設定できない場合、レースフリーはありません'BeginInvokeUnlessWindowIsGone'を行う方法です。あなたは 'BeginInvoke'をして例外を飲み込むだけです。 – supercat
@supercatが合意した、それは例外的なケースだと思うのです(そしてtry/catchは正当化されます)。 –
発信側から、ええ。それはデザインは小さいですが、悪意のある点は、BeginInvoke(およびイベント)の多くが、呼び出し側ではなくターゲットの利益のために発生することをフレームワークが認識できないことに由来します。 (例えば、WeakEventまたはWeakDelegateがないために)同様の臭いがイベントで発生する。 – supercat