コマンドを起動するコントロールがあるとします。
<Button Command="New"/>
ユーザーがコマンドをダブルクリックした場合にコマンドが 2 回起動されるのを防ぐ方法はありますか?
編集:この場合の重要な点は、WPFでCommandingモデルを使用していることです。
ボタンが押されるたびに、コマンドが実行されるようです。ボタンを無効にするか非表示にする以外に、これを防ぐ方法はありません。
コマンドを起動するコントロールがあるとします。
<Button Command="New"/>
ユーザーがコマンドをダブルクリックした場合にコマンドが 2 回起動されるのを防ぐ方法はありますか?
編集:この場合の重要な点は、WPFでCommandingモデルを使用していることです。
ボタンが押されるたびに、コマンドが実行されるようです。ボタンを無効にするか非表示にする以外に、これを防ぐ方法はありません。
かなりの処理時間を必要とするコードを含むイベント ハンドラーは、問題のボタンの無効化に遅延をもたらす可能性があります。ハンドラー内でコードの無効化行が呼び出される場所に関係なく。
以下の証明を試してみると、無効化/有効化がイベントの登録に相関していないことがわかります。ボタン クリック イベントは引き続き登録され、処理されます。
矛盾による証明 1
private int _count = 0;
private void btnStart_Click(object sender, EventArgs e)
{
btnStart.Enabled = false;
_count++;
label1.Text = _count.ToString();
while (_count < 10)
{
btnStart_Click(sender, e);
}
btnStart.Enabled = true;
}
矛盾2による証明
private void form1_load(object sender, EventArgs e)
{
btnTest.Enabled = false;
}
private void btnStart_Click(object sender, EventArgs e)
{
btnTest.Enabled = false;
btnTest_click(sender, e);
btnTest_click(sender, e);
btnTest_click(sender, e);
btnTest.Enabled = true;
}
private int _count = 0;
private void btnTest_click(object sender, EventArgs e)
{
_count++;
label1.Text = _count.ToString();
}
ダブル、トリプル、クワッドクリックをブロックするためのシンプルで効果的な
<Button PreviewMouseDown="Button_PreviewMouseDown"/>
private void Button_PreviewMouseDown(object sender, MouseButtonEventArgs e)
{
if (e.ClickCount >= 2)
{
e.Handled = true;
}
}
私は同じ問題を抱えていましたが、これは私にとってはうまくいきました:
<Button>
<Button.InputBindings>
<MouseBinding Gesture="LeftClick" Command="New" />
</Button.InputBindings>
</Button>
WPF Commanding ではクリック ハンドラーをいじるのに十分な制御ができないと仮定すると、コマンドが最後に実行された時刻を記憶し、特定の時間内にコマンドが要求された場合に終了するコードをコマンド ハンドラーに追加できますか? (以下のコード例)
ダブルクリックの場合、ミリ秒以内に 2 回イベントを受け取るので、2 番目のイベントは無視するという考え方です。
次のようなもの: (コマンド内)
// warning: I haven't tried compiling this, but it should be pretty close
DateTime LastInvoked = DateTime.MinDate;
Timespan InvokeDelay = Timespan.FromMilliseconds(100);
{
if(DateTime.Now - LastInvoked <= InvokeDelay)
return;
// do your work
}
(注: 単純な古いクリック ハンドラーである場合は、次のアドバイスに従ってください: http://blogs.msdn.com/oldnewthing/archive/2009/04/29/9574643.aspx )
このように解決しました... async では、この Click を呼び出すボタンの余分なクリックを効果的にブロックする他の方法を見つけることができませんでした:
private SemaphoreSlim _lockMoveButton = new SemaphoreSlim(1);
private async void btnMove_Click(object sender, RoutedEventArgs e)
{
var button = sender as Button;
if (_lockMoveButton.Wait(0) && button != null)
{
try
{
button.IsEnabled = false;
}
finally
{
_lockMoveButton.Release();
button.IsEnabled = true;
}
}
}
Command
コマンドの実行中に a を使用してCanExecute()
return false にするのと同じくらい簡単だと思うでしょう。あなたは間違っているでしょう。CanExecuteChanged
明示的に上げたとしても:
public class TestCommand : ICommand
{
public void Execute(object parameter)
{
_CanExecute = false;
OnCanExecuteChanged();
Thread.Sleep(1000);
Console.WriteLine("Executed TestCommand.");
_CanExecute = true;
OnCanExecuteChanged();
}
private bool _CanExecute = true;
public bool CanExecute(object parameter)
{
return _CanExecute;
}
private void OnCanExecuteChanged()
{
EventHandler h = CanExecuteChanged;
if (h != null)
{
h(this, EventArgs.Empty);
}
}
public event EventHandler CanExecuteChanged;
}
このコマンドにウィンドウの への参照があり、が呼び出されたときにDispatcher
使用された場合、機能すると思われます。Invoke
OnCanExecuteChanged
この問題を解決するには、いくつかの方法を考えることができます。One's JMarsch のアプローチ:Execute
が呼び出されたときに単純に追跡し、最後の数百ミリ秒以内に呼び出された場合は何もせずに救済します。
より堅牢な方法は、Execute
メソッドを startBackgroundWorker
にして実際の処理を実行させ、CanExecute
returnを持たせ、タスクの完了時に(!BackgroundWorker.IsBusy)
レイズすることです。CanExecuteChanged
ボタンは、返さCanExecute()
れるとすぐに再クエリをExecute()
実行する必要があります。これは即座に行われます。
これを防ぐ には、 MVVMLightToolkitEventToCommand
のクラスを使用できます。
Click イベントを処理しEventToCommand
、ビューからビューモデルに送信します (EventTrigger
これを行うために使用できます)。
ビューに設定し、ビューモデルにメソッドMustToggleIsEnabled="True"
を実装します。コマンドの実行が開始されたときに false を返し、コマンドが完了すると true に戻るように
設定します。CanExecute()
CanExecute()
これにより、コマンドの処理中はボタンが無効になります。
フラグを設定できます
bool boolClicked = false;
button_OnClick
{
if(!boolClicked)
{
boolClicked = true;
//do something
boolClicked = false;
}
}
シンプルで洗練された解決策は、ダブルクリックのシナリオで 2 回目のクリックで動作を無効にする反応を作成することです。使い方はとても簡単です:
<Button Command="New">
<i:Interaction.Behaviors>
<behaviors:DisableDoubleClickBehavior />
</i:Interaction.Behaviors>
</Button>
振る舞い (振る舞いについての詳細 - https://www.jayway.com/2013/03/20/behaviors-in-wpf-introduction/ )
using System.Windows.Controls;
using System.Windows.Input;
using System.Windows.Interactivity;
public class DisableDoubleClickBehavior : Behavior<Button>
{
protected override void OnAttached()
{
base.OnAttached();
AssociatedObject.PreviewMouseDoubleClick += AssociatedObjectOnPreviewMouseDoubleClick;
}
private void AssociatedObjectOnPreviewMouseDoubleClick(object sender, MouseButtonEventArgs mouseButtonEventArgs)
{
mouseButtonEventArgs.Handled = true;
}
protected override void OnDetaching()
{
AssociatedObject.PreviewMouseDoubleClick -= AssociatedObjectOnPreviewMouseDoubleClick;
base.OnDetaching();
}
}
コントロールがSystem.Windows.Forms.Controlから派生している場合は、ダブルクリックイベントを使用できます。
System.Windows.Forms.Controlから派生していない場合は、代わりにマウスダウンを接続し、クリック数を確認します== 2:
private void Button_MouseDown(object sender, MouseButtonEventArgs e)
{
if (e.ClickCount == 2)
{
//Do stuff
}
}
これにより、検証が成功したかどうかがチェックされ、成功した場合はボタンが無効になります。
private void checkButtonDoubleClick(Button button)
{
System.Text.StringBuilder sbValid = new System.Text.StringBuilder();
sbValid.Append("if (typeof(Page_ClientValidate) == 'function') { ");
sbValid.Append("if (Page_ClientValidate() == false) { return false; }} ");
sbValid.Append("this.value = 'Please wait...';");
sbValid.Append("this.disabled = true;");
sbValid.Append(this.Page.ClientScript.GetPostBackEventReference(button, ""));
sbValid.Append(";");
button.Attributes.Add("onclick", sbValid.ToString());
}