今回私がハマったのは、C#のWinFormsでuseWaitCursorを使ったあとに元のカーソルに戻らない!というバグ。
たぶんこれ、WinFormsのバグですよ。
っていうのもね。下記のようなコードを書いたわけです。
try{
this.UseWaitCursor = true;
// 時間のかかるイベント。非同期実装
MessageBox.Show("処理が終わりました。")
}catch(Exception exception){
MessageBox.Show("エラーが発生しました。")
}finally{
this.UseWaitCursor = false;
}
ありがちなコードですね。
処理に時間がかかるから、非同期実装して、その前後にUseWaitCursorを置く。
めちゃくちゃシンプルです。
私の場合、try catch finallyを仕掛けて途中でエラーが出ても戻るようにしています。
なのに!!
なのに!!!
数回に1回待機中からもとに戻らんことがある!!!
っということで、UseWaitCursorから戻らないときに内部的にどのようなステータスを持っているのか見てみました。
Cursorに関係するプロパティ
まずはCursorに関するプロパティはどこにあるのか?ということですが、下記の通りです。
- Control.Cursor
- Control.UseWaitCursor
- Application.UseWaitCursor
- Cursor.Current
続いて、この事象が発生した時のすべてのプロパティを見ていきます。
MessageBox.Show(Cursor.Current.ToString());
適当なボタンに上記のプログラムを仕込んで、事象が発生したらボタンを押して、中身を見るようにします。
- Cursor.CurrentはDefaultになってる。
続いてApplication.UseWaitCursorを見てみる。
実行前はこんな感じ。
事象が発生している状態はこんな感じ。
続いて各コントロールのUseWaitCursorのプロパティを見てみる。
MessageBox.Show(GetWaitCursorStatus(this));
これを仕込んで、GetWaitCursorStatusは下記の関数を作った。
private string GetWaitCursorStatus(Control control)
{
var str = $@"{control.Name} : {control.UseWaitCursor.ToString()}";
foreach (Control c in control.Controls)
{
str += Environment.NewLine + GetWaitCursorStatus(c);
}
return str;
}
コントロールの中にあるコントロールを再帰的に取得して、中身を見てくだけの関数。
事象が発生する前はこんな感じ。
全部Falseになってる。
事象が発生した時のプロパティはこんな感じ。
うん。
変わりないね。
っで、最後のControl.Cursorを見てみる。
private string GetWaitCursorStatus(Control control)
{
var str = $@"{control.Name} : {control.Cursor.ToString()}";
foreach (Control c in control.Controls)
{
str += Environment.NewLine + GetWaitCursorStatus(c);
}
return str;
}
さっきのコードをちょっと修正して実行。
まあ普通って感じですね。
事象発生してるときはこんな感じ。
はい見つけました。
Control.CursorがWaitCursorになっててもとに戻ってない!!!!
ということでバグが発生しているコードに、下記を追加してFix!!
dgv_MainGrid.Cursor = Cursor.Current;
try{
this.UseWaitCursor = true;
// 時間のかかるイベント。非同期実装
MessageBox.Show("処理が終わりました。")
}catch(Exception exception){
MessageBox.Show("エラーが発生しました。")
}finally{
this.UseWaitCursor = false;
dgv_MainGrid.Cursor = Cursor.Current;
}
コメント