2

VS2005 で実行されているプログラムと、実行可能ファイルを直接実行しているプログラムとの間に奇妙な違いがありました。基本的に、Application.DoEvents()呼び出し内のメソッドで例外がスローされた場合、Visual Studio 内で実行しているときに例外をキャッチできます。コンパイルされた実行可能ファイルを実行すると、例外がキャッチされず、プログラムがクラッシュします。

問題を示す簡単なコードを次に示します。標準の winforms ボイラープレートと 2 つのボタンとラベルを想定します。

これを実行するには、開始ボタンをクリックして 10 秒のカウントを開始します。10 秒が経過する前に、中止ボタンを押します。の内部で例外がスローされますDoEvents()。例外をキャッチする必要があります。これは、Visual Studio 内で実行している場合にのみ発生します。

    private void StartButton_Click(object sender, EventArgs e) {
        DateTime start = DateTime.Now;

        try {
            while (DateTime.Now - start < new TimeSpan(0, 0, 10)) {
                this.StatusLabel.Text = DateTime.Now.ToLongTimeString();
                Application.DoEvents();
            }

            MessageBox.Show("Completed with no interuption.");
        } catch (Exception) {
            MessageBox.Show("User aborted.");                
        }
    }

    private void ButtonAbort_Click(object sender, EventArgs e) {
        throw new Exception("aborted");
    }

これらの例外をキャッチできるようにしたい。それを機能させる方法はありますか?

アップデート:

re-entrant-headache-inducing 以外のアプローチも検討したいと思いDoEvents()ます。しかし、私はよりうまく機能すると思われるものを見つけていません。私のシナリオは、いくつかの科学機器を制御している長時間実行ループがあり、温度が安定するなどを頻繁に待たなければならないというものです。ユーザーがプロセスを中止できるようにしたいので、プロセスが最初に開始されたサイトでキャッチするカスタム例外を単にスローする中止ボタンを用意しました。それは完璧な解決策のように思えました。何らかの理由で機能しないという事実を除いて。

これを機能させることができない場合、より良いアプローチはありますか?

更新 2:

これを Main() の最初の行として追加すると、実行可能ファイルとして機能しますが、VS では機能しないため、状況が逆になります。クレイジーなことは、ノーオペレーションのように見えることです。これがどのように機能するか理解できます。

Application.ThreadException += delegate(
        object sender, 
        System.Threading.ThreadExceptionEventArgs e
    ) 
    { throw e.Exception; };

これは非常識です。

4

4 に答える 4

1

古いニュースを取り上げようとしているわけではありませんが、私はこの同じ問題に苦しんでいて、解決策が見つからなかったからです. バックグラウンド ワーカーを実行していて、ユーザーがメイン アプリケーション スレッドに戻って他の作業を行っていて、バックグラウンド ワーカーにある同じ関数を実行したい場合、Application.DoEvents() が最善の方法のように思えますが、それでも実行できます。これを使って。問題は、RunWorkerCompleted イベントにコードがあるという事実にあります。CancelAsync でワーカー自体をキャンセルすると、RunWorkerCompleted 内に存在するものはすべて実行されます。問題は、通常、RunWorkerCompleted にあるものはすべて GUI にアクセスしており、Application.DoEvents() の実行中に GUI にアクセスできないことです。RunWorkerCompmleded からコードを削除し、それを ReportProgress 関数に組み込む方がより受け入れられます。ただし、メイン スレッドが別の実行を要求していないことを確認するために、reportprogress 関数の直前にチェック イベントをスローする必要があります。reportprogress の直前に次のようなものがあります。

if (backgroundWorker1.CancellationPending == true){
     e.Cancel = true;
     return;
}
backgroundWorker1.ReportProgress(0);

したがって、バックグラウンド スレッドはすべての作業を行っており、ReportProgress がこのチェックをスローする直前に実行されます。このように、ユーザーが別のアイテムでこのクエリを実際に実行したいと言った場合、次のようなループで待機します。

if (backgroundWorker1.IsBusy == true){
     backgroundWorker1.CancelAsync();
     While(backgroundWorker1.CancellationPending == true){
          Application.DoEvents();
     }
}

これを使用するのは明らかに悪い習慣ですが、例外を取り除くことができます。私が取り組んでいるプロジェクトの変更を開始するまで、私はこれを探し回り、エラーが発生している唯一の理由は、同時にメインスレッドにアクセスしていることが原因であることがわかりました。おそらくこれで炎上するでしょうが、答えがあります。

于 2010-07-01T01:20:14.667 に答える