もくじ
■連打防止関連
ボタン押したときに時間がかかる処理をawaitでやるときに、ボタン連打を防止したい
→https://qiita.com/tera1707/items/a6f11bd3bf2dbf97dd40
ボタン押したときに時間がかかる処理をawaitでやるときに、ボタン連打を防止したい その2
→https://qiita.com/tera1707/items/946116bf32d0f1203006
やりたいこと
prism(6.3)を使ったWPFアプリで、下記のような感じでボタンを押したときの処理を書きたい。
<Button Content="ボタン" Command="{Binding ButtonCommand}"/>
// コンストラクタ
public UserControl1ViewModel()
{
this.ButtonCommand = new DelegateCommand(async () =>
{
// 時間のかかる処理
await Task.Delay(500);
});
}
が、上記をそのまま実行して、ボタンを連打すると、「時間のかかる処理」が終わってボタンの処理を抜ける前に何度も「時間のかかる処理」が走ってしまう。
これを、一度ボタンを押したら一連のボタン処理が終わるまでボタンを押せないように(ボタンを押したときの処理が同時に複数回走ってしまわないように)したい。
今回やったやり方
DelegateCommand
が持つObservesProperty
メソッドとDelegateCommand
の引数が2つある方のコンストラクタの第二引数canExecuteMethod
を使用する。
サンプル
// 有効無効を設定するプロパティを一つ作成する
private bool _flag = true;
public bool Flag
{
get { return this._flag; }
set { this.SetProperty(ref _flag, value); }
}
・
・
・
// コンストラクタ
public UserControl1ViewModel()
{
this.ButtonCommand = new DelegateCommand(async() =>
{
Flag = false; // ボタン押下直後に有効無効フラグをOFF(無効)にする
await Task.Delay(500); // 時間のかかる処理
Flag = true; // 処理終了後に有効無効フラグをON(有効)にする
},
() => Flag) // CanExecuteでFlagを見て有効無効を制御
.ObservesProperty(() => Flag); // ObservesPropertyでFlagを監視するよう指定する
}
やったことは言葉で書くと下記のとおり。
- 準備
- 有効無効を設定するためのプロパティを1つ作成する
- DelegateCommandをnewするときに
- 第一引数の、ボタンを押したときの処理を書くActionの冒頭でフラグをON、最後でフラグをOFFさせる
- 第二引数のCanExecuteで、そのフラグを返す(フラグのONOFFで有効無効を制御できるようにする)
- ObservesPropertyで、Flagが変化したらCanExecuteを実行してくれるようにする
備考
時間のかかる処理を実行中に「無効」になっている間、スタイルによってはボタンがグレーアウトしているように見える。
そういうのが気になるという場合は、無効でも見た目が変わらないようにするとか、さらなる逃げをしないといけなくなる可能性がある。
またなにより、そういうことをしたいボタンが一つだったらこのやり方も現実的ではあるが、たくさんこういうボタンが画面上にあったとしたら、似たフラグだらけになりそう。
もっとうまいことできないものか...
参考
AsyncReactiveCommandでWPFのお手軽ダブルクリック抑制
https://qiita.com/soi/items/eca0601ad0fc4e401623
ReactivePropertyを使うと、今回やりたいことが簡単にできる様子。
ただ、元々ReactivePropertyを使っていたら使いたいが、今回の私の場合、二度押し防止のためだけにReactivePropertyを入れるというのもどうなのか...