2009-05-08 8 views
9

Brennen Da haben Sie eine Steuerung, die einen Befehl ausgelöst:Prevent Doppelklick aus Doppel einen Befehl

<Button Command="New"/> 

Gibt es eine Möglichkeit von dem Befehl zu verhindern zweimal gefeuert zu werden, wenn der Benutzer doppelt klickt auf dem Befehl ?

EDIT: Was in diesem Fall bedeutsam ist, ist, dass ich das Modell Commanding in WPF verwende.

Es scheint, dass der Befehl ausgeführt wird, wenn die Taste gedrückt wird. Ich sehe keine Möglichkeit, dies zu verhindern, außer den Knopf zu deaktivieren oder zu verstecken.

+0

Es scheint nicht trotzdem zu sein, die interne Handhabung des Klickereignisses durch WPF anzupassen/zu überschreiben? –

Antwort

1

Vielleicht sollte die Schaltfläche deaktiviert werden nach dem ersten Klick und bis die Verarbeitung abgeschlossen ist?

+0

Ich glaube, das ist im Wesentlichen, was ich tun muss. –

+0

Ich verstehe wirklich nicht, wie die Antwort akzeptiert wurde. Wie sollte nach dem ersten Klick deaktiviert werden, wenn das Ereignis als Async geändert wurde? Und andere; Synchronisierungsprozess verhindert nicht auch Doppelklick. –

+0

Diese Antwort ist nicht korrekt, da das Ereignis asynchron ist. – TeoVr81

3

Sie könnten ein Flag

bool boolClicked = false; 
button_OnClick 
{ 
    if(!boolClicked) 
    { 
     boolClicked = true; 
     //do something 
     boolClicked = false; 
    } 
} 
+2

Ich würde ein Try hinzufügen {boolClicked = true; Etwas tun(); } Schließlich {boolClicked = false;}, um sicherzustellen, dass das Flag zurückgesetzt wird. Prost. – SRO

+0

@nathan koop hat nicht versucht, Ihren Code in der echten Xamarin Forms App zu testen. –

0

gesetzt Wenn Ihre Steuerung von System.Windows.Forms.Control leitet, können Sie die double click event verwenden können.

Wenn es nicht aus System.Windows.Forms.Control nicht ableiten, dann wire up mousedown statt und bestätigen Sie die Klickzahl == 2:

private void Button_MouseDown(object sender, MouseButtonEventArgs e) 
{ 
    if (e.ClickCount == 2) 
    { 
     //Do stuff 
    } 
} 
+0

Dies ist ein WPF-Steuerelement ... Es stammt von System.Windows.Controls.Control –

+0

Dann können Sie dies verwenden: http://msdn.microsoft.com/en-us/library/system.windows.input. mousebuttoneventargs.clickcount.aspx Oder habe ich missverstanden? –

+0

Das Ziel war nicht, das Doppelklickereignis zu behandeln; meine Absicht ist es zu unterdrücken. –

3

Unter der Annahme, dass WPF kommandier nicht geben Ihnen genug Kontrolle Kannst du mit dem Click-Handler umgehen, könntest du Code in den Command-Handler schreiben, der sich an das letzte Mal erinnert, als der Befehl ausgeführt wurde und beendet wird, wenn er innerhalb eines bestimmten Zeitraums angefordert wird? (Codebeispiel unten)

Die Idee ist, dass Sie das Ereignis zweimal innerhalb von Millisekunden erhalten, wenn Sie einen Doppelklick ausführen, also ignorieren Sie das zweite Ereignis.

So etwas wie: (innerhalb der Command)

 

// 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 
} 
 

(Anmerkung: wenn es nur ein einfacher alter Click-Handler, würde ich diesen Rat sagen folgen: http://blogs.msdn.com/oldnewthing/archive/2009/04/29/9574643.aspx)

+0

Gute Verbindung. Die Entprelltechnik, auf die du dich beziehst, ist genau das, worüber ich spreche. Stellt sich heraus, dass unser WPF-Programm manchmal falsch funktioniert, wenn Sie auf die Schaltflächen doppelklicken, die nur angeklickt werden sollen. –

-2

Diese Kontrollen Wenn die Validierung bestanden wurde und wenn dies der Fall ist, wird die Schaltfläche deaktiviert.

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()); 
    } 
+0

Wow. Ich bin mir nicht sicher, was hier vor sich geht, aber es sieht so aus, als würden Sie ASP.NET oder etwas anderes annehmen. Es gibt keine Seite, kein ClientScript und keinen Postback. –

+0

Ja, falscher Ort, um dies zu posten. Dies ist für Standard-asp.net, nicht wpf. – ta4ka

3

können Sie verwenden, um die EventToCommand Klasse im MVVMLightToolkit dies zu verhindern.

Behandeln Sie das Click-Ereignis und senden Sie es von EventToCommand aus Ihrer Sicht an Ihr Ansichtsmodell (Sie können dazu EventTrigger verwenden).
Setzen Sie in Ihrer Ansicht MustToggleIsEnabled="True" und implementieren Sie eine CanExecute() Methode in Ihrem Viewmodel.
Setzen Sie CanExecute() auf false, wenn der Befehl ausgeführt wird, und auf true, wenn der Befehl ausgeführt wurde.

Dies wird die Schaltfläche für die Dauer der Verarbeitung des Befehls deaktivieren.

+1

Das Fleisch von dem, was Sie sagen: Wenn die Schaltfläche an einen Befehl gebunden ist, deaktivieren Sie den Befehl (CanExecute() = false), bis der Befehl verarbeitet ist. –

+0

@Josh G: Ja tatsächlich! – stombeur

7

hatte ich das gleiche Problem und das ist für mich gearbeitet:

<Button> 
    <Button.InputBindings> 
      <MouseBinding Gesture="LeftClick" Command="New" /> 
    </Button.InputBindings> 
</Button> 
+0

Wow. Wenn das funktioniert, wäre das fantastisch. Ich werde es irgendwann versuchen müssen. –

+0

Ich kann bestätigen, dass dies auch für mich funktioniert hat, danke! – Simone

+0

Ernsthaft, wie hast du das gefunden? – Snake

4

Man sollte meinen, dass es eine Command und machen CanExecute() return false wie die Verwendung während der Befehl ausgeführt wird, so einfach sein würde. Du würdest dich irren. Auch wenn Sie CanExecuteChanged explizit erhöhen:

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; 
} 

Ich vermute, dass, wenn dieser Befehl Dispatcher, einen Verweis auf das Fenster des hatte und verwendet Invoke wenn es OnCanExecuteChanged genannt, würde es funktionieren.

Ich kann mir eine Reihe von Möglichkeiten vorstellen, um dieses Problem zu lösen. Der Ansatz von JMarsch: einfach nachverfolgen, wenn Execute aufgerufen wird, und ohne dass etwas ausgeführt wird, wenn es in den letzten paar hundert Millisekunden aufgerufen wurde.

Eine robustere Art und Weise könnte die Execute Methode ein BackgroundWorker startet die eigentliche Verarbeitung zu tun, muß CanExecute Rückkehr (!BackgroundWorker.IsBusy) und erhöht CanExecuteChanged in, wenn die Aufgabe abgeschlossen ist. Die Schaltfläche sollte CanExecute() erneut requery, sobald Execute() zurückgibt, was es sofort tun wird.

+0

Ich denke, dass Sie nicht viele Taps (genug schnell) getestet haben, wenn Sie es testen. Es funktioniert nicht ... –

14

Die überprüfte Antwort auf diese Frage, eingereicht von vidalsasoon, ist falsch und es ist falsch für all die verschiedenen Möglichkeiten, die diese Frage gestellt wurde.

Es ist möglich, dass jeder Event-Handler, der Code enthält, der eine signifikante Prozesszeit benötigt, zu einer Verzögerung der Deaktivierung der Schaltfläche führen kann. unabhängig davon, wo die deaktivierende Codezeile innerhalb des Handlers aufgerufen wird.

Probieren Sie die unten stehenden Beweise und Sie werden sehen, dass disable/enable keine Korrelation mit der Registrierung von Ereignissen hat. Das Klickereignis ist weiterhin registriert und wird weiterhin verarbeitet.

Widerspruchsbeweis 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; 

} 

Nachweis von Contradition 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(); 
} 
+0

Das OP verwendet MVVM (bindend) und Befehle für WPF. Sie verwenden den WinForms- "Ereignis" -Ansatz, der hier nicht zur Anwendung kommt. – vidalsasoon

+1

@vidalsasoon Sie haben richtig, dass ich Winforms als Demonstration verwendet habe. Der Schlüsselpunkt ist jedoch, dass die Ereignisregistrierung von anderen Steuerelementen/Schaltflächen isoliert ist und die Eigenschaft aktiviert bzw. deaktiviert wird, und das Deaktivieren einer Schaltfläche verhindert nicht, dass ein abonnierter Ereignishandler Code ausführt. Dies gilt für WPF und Winforms. Ich wollte nur darauf hinweisen, dass die überprüfte Antwort zu diesem Beitrag nicht korrekt ist. Nichts für ungut beabsichtigt. Ich habe den Fehler selbst gemacht. – JDennis

5

Einfache & Effective zum Blockieren Doppel-, Dreifach-, Vierfach und Klicks

<Button PreviewMouseDown="Button_PreviewMouseDown"/> 

private void Button_PreviewMouseDown(object sender, MouseButtonEventArgs e) 
{ 
    if (e.ClickCount >= 2) 
    { 
     e.Handled = true; 
    } 
} 
2

Wir lösten es so ... mit Asynchron wir keine andere Möglichkeit, um zusätzliche Klicks, um effektiv zu blockieren auf die Schaltfläche, die diese Click ruft gefunden:

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; 
     } 
    } 
} 
2

Eine einfache und elegante Lösung ist, ein Verhalten zu erstellen Deaktivierung der Reaktion beim zweiten Klick im Doppelklick-Szenario. Das ist ziemlich einfach zu bedienen:

<Button Command="New"> 
      <i:Interaction.Behaviors> 
      <behaviors:DisableDoubleClickBehavior /> 
      </i:Interaction.Behaviors> 
    </Button> 

Verhalten (mehr über Verhaltensweisen - 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(); 
    } 
} 
0

das gleiche Problem hatte, löste es durch angebracht Verhalten verwenden.

namespace VLEva.Core.Controls 
{ 
    /// <summary></summary> 
    public static class ButtonBehavior 
    { 
     /// <summary></summary> 
     public static readonly DependencyProperty IgnoreDoubleClickProperty = DependencyProperty.RegisterAttached("IgnoreDoubleClick", 
                                typeof(bool), 
                                typeof(ButtonBehavior), 
                                new UIPropertyMetadata(false, OnIgnoreDoubleClickChanged)); 

     /// <summary></summary> 
     public static bool GetIgnoreDoubleClick(Button p_btnButton) 
     { 
      return (bool)p_btnButton.GetValue(IgnoreDoubleClickProperty); 
     } 

     /// <summary></summary> 
     public static void SetIgnoreDoubleClick(Button p_btnButton, bool value) 
     { 
      p_btnButton.SetValue(IgnoreDoubleClickProperty, value); 
     } 

     static void OnIgnoreDoubleClickChanged(DependencyObject p_doDependencyObject, DependencyPropertyChangedEventArgs e) 
     { 
      Button btnButton = p_doDependencyObject as Button; 
      if (btnButton == null) 
       return; 

      if (e.NewValue is bool == false) 
       return; 

      if ((bool)e.NewValue) 
       btnButton.PreviewMouseLeftButtonDown += new MouseButtonEventHandler(btnButton_PreviewMouseLeftButtonDown); 
      else 
       btnButton.PreviewMouseLeftButtonDown -= btnButton_PreviewMouseLeftButtonDown; 
     } 

     static void btnButton_PreviewMouseLeftButtonDown(object sender, MouseButtonEventArgs e) 
     { 
      if (e.ClickCount >= 2) 
       e.Handled = true; 
     } 

    } 
} 

und dann nur die Eigenschaft auf TRUE gesetzt, entweder direkt in XAML durch einen Stil zu erklären, so dass es auf einmal alle Tasten beeinflusst werden. (Vergessen Sie nicht die XAML-Namespace-Deklaration)

Verwandte Themen