17

コマンドを起動するコントロールがあるとします。

<Button Command="New"/>

ユーザーがコマンドをダブルクリックした場合にコマンドが 2 回起動されるのを防ぐ方法はありますか?

編集:この場合の重要な点は、WPFでCommandingモデルを使用していることです。

ボタンが押されるたびに、コマンドが実行されるようです。ボタンを無効にするか非表示にする以外に、これを防ぐ方法はありません。

4

16 に答える 16

17

かなりの処理時間を必要とするコードを含むイベント ハンドラーは、問題のボタンの無効化に遅延をもたらす可能性があります。ハンドラー内でコードの無効化行が呼び出される場所に関係なく。

以下の証明を試してみると、無効化/有効化がイベントの登録に相関していないことがわかります。ボタン クリック イベントは引き続き登録され、処理されます。

矛盾による証明 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();
}
于 2013-05-06T21:22:58.357 に答える
13

ダブル、トリプル、クワッドクリックをブロックするためのシンプルで効果的な

<Button PreviewMouseDown="Button_PreviewMouseDown"/>

private void Button_PreviewMouseDown(object sender, MouseButtonEventArgs e)
{
    if (e.ClickCount >= 2)
    {
        e.Handled = true;
    }
}
于 2014-04-02T14:27:40.283 に答える
12

私は同じ問題を抱えていましたが、これは私にとってはうまくいきました:

<Button>
    <Button.InputBindings>
            <MouseBinding Gesture="LeftClick" Command="New" />
    </Button.InputBindings>
</Button>
于 2011-08-25T20:19:31.187 に答える
7

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 )

于 2009-05-08T20:34:44.040 に答える
7

このように解決しました... 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;
        }
    }
}
于 2015-09-30T19:49:48.573 に答える
5

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使用された場合、機能すると思われます。InvokeOnCanExecuteChanged

この問題を解決するには、いくつかの方法を考えることができます。One's JMarsch のアプローチ:Executeが呼び出されたときに単純に追跡し、最後の数百ミリ秒以内に呼び出された場合は何もせずに救済します。

より堅牢な方法は、Executeメソッドを startBackgroundWorkerにして実際の処理を実行させ、CanExecutereturnを持たせ、タスクの完了時に(!BackgroundWorker.IsBusy)レイズすることです。CanExecuteChangedボタンは、返さCanExecute()れるとすぐに再クエリをExecute()実行する必要があります。これは即座に行われます。

于 2011-08-25T21:24:55.227 に答える
5

これを防ぐ には、 MVVMLightToolkitEventToCommandのクラスを使用できます。

Click イベントを処理しEventToCommand、ビューからビューモデルに送信します (EventTriggerこれを行うために使用できます)。
ビューに設定し、ビューモデルにメソッドMustToggleIsEnabled="True"を実装します。コマンドの実行が開始されたときに false を返し、コマンドが完了すると true に戻るように 設定します。CanExecute()
CanExecute()

これにより、コマンドの処理中はボタンが無効になります。

于 2011-03-22T13:55:14.500 に答える
4

フラグを設定できます

bool boolClicked = false;
button_OnClick
{
    if(!boolClicked)
    {
        boolClicked = true;
        //do something
        boolClicked = false;
    }
}
于 2009-05-08T19:15:42.357 に答える
3

シンプルで洗練された解決策は、ダブルクリックのシナリオで 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();
    }
}
于 2016-11-03T12:43:32.273 に答える
0

コントロールがSystem.Windows.Forms.Controlから派生している場合は、ダブルクリックイベントを使用できます。

System.Windows.Forms.Controlから派生していない場合は、代わりにマウスダウンを接続し、クリック数を確認します== 2:

private void Button_MouseDown(object sender, MouseButtonEventArgs e)
{
    if (e.ClickCount == 2)
    {
       //Do stuff
    }
 }
于 2009-05-08T19:24:47.717 に答える
-3

これにより、検証が成功したかどうかがチェックされ、成功した場合はボタンが無効になります。

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());
    }
于 2009-12-15T21:12:51.143 に答える