1

Windows フォーム イベントで奇妙な問題が発生しました。正確には、KryptonHeaderGroupの ButtonSpec Click イベントですが、プレーン バニラでも発生しSystem.Windows.Forms.Buttonます。

クリック イベントでは、ユーザー インターフェイスがダウンし (ラベルとキャンセル ボタンが残っています)、以前のユーザー入力から高価な LINQ クエリが作成され、コンパイルされてから実行されます。Application.DoEvents()foreach には、実際にクエリを実行する呼び出しがあります (オブジェクトへの LINQ であるため、遅延しています) 。これにより、ユーザーはキャンセルを押すことができます。その後、DoEventsキャンセル フラグがテストされ、foreach がキャンセルされ、いくつかのクリーンアップが行われます。ここまでは順調ですね。

ただし、最初のいくつかの結果が表示された後に [キャンセル] ボタンを押すと (ラベルには既にいくつの結果が表示されているかが示されます)、Click イベント ハンドラー全体が再起動されます。いくつかのトレースを追加した後、これは前のハンドラーが戻る前に発生したようです。つまり、DoEvents呼び出しの 1 つで発生します。もちろん、ボタンはもう一度押されません。ボタンがイベント ハンドラーで無効になっている場合は発生しません。しかし、ボタンは押されていないので、その Click イベントを再度発生させるべきではありません。

私は困惑しています。明らかに回避策はボタンを無効にすることですが、ここで実際の問題が何であるかを知りたいです。DoEventsハンドラが終了する前に が呼び出された場合、イベント ハンドラを再起動できますか? DoEventsイベントハンドラーでの呼び出しは推奨/許可されていませんか? しかし、すべてがイベント駆動型アプリケーションのイベント ハンドラーであるため、それを呼び出すことはできません :)

この質問に答えるために必要な追加のヒント:

  • LINQ クエリは、最初の結果を提供する前、つまり最初のDoEvents呼び出しが行われる前に、最初は長い時間がかかります。
  • LINQ クエリは GUI スレッドで実行されます。ユーザーが残りのアプリケーションにアクセスできるようにするのは意味がないためです。アクセスは、GUI と LINQ クエリの両方が使用する基になる API に干渉するためです。
  • アンロードできるようにするには、LINQ クエリを別のアプリ ドメインにロードしてそこで実行する必要があることはわかっています。ただし、一般的なユーザーが実行するクエリはほとんどなく、結果のアセンブリは (同じクエリ文字列に対して) キャッシュされます。
  • ブレークポイントを有効にしている場合 (ため息- ハイゼンベルグ、誰か?)、または後でクエリ中にキャンセルした場合、問題は発生しなくなりました。

それが単なる推測であっても、動作を説明するものは何でも感謝します:)

4

1 に答える 1

3

DoEvents は GUI メッセージを処理するため、それ以上のクリックやメッセージを処理できます。イベントハンドラーで呼び出さないことをお勧めします。正直に言うと、これを使用することはまったく避けたいと思います。

MSDN から:このメソッドを呼び出すと、メッセージでイベントが発生した場合にコードが再入力される可能性があります。

長期:

これが実行時間の長いクエリである場合は、バックグラウンド スレッドでの実行を検討し、ボタンを無効にします。これは、このタイプのアクティビティの一般的なパターンです。

于 2009-11-23T11:23:34.440 に答える