2009-05-08 17 views
9

Biorąc pod uwagę, że masz kontrolę, która wystrzeliwuje polecenie:Prevent kliknij dwukrotnie z podwójnym wystrzałem z polecenia

<Button Command="New"/> 

Czy istnieje sposób, aby zapobiec polecenie wyrzuceniu dwukrotnie Jeśli użytkownik kliknie dwukrotnie na komendzie ?

EDIT: Co jest istotne w tym przypadku jest to, że używam modelu w WPF Commanding.

Wygląda na to, że po naciśnięciu przycisku polecenie zostanie wykonane. Nie widzę żadnego sposobu, aby temu zapobiec, oprócz wyłączenia lub ukrycia przycisku.

+0

Wygląda na to, że nie ma potrzeby dostosowywania/przesłonięcia wewnętrznej obsługi zdarzenia kliknięcia przez WPF? –

Odpowiedz

1

Być może przycisk powinien być wyłączony po pierwszym kliknięciu i do zakończenia przetwarzania?

+0

Uważam, że to jest zasadniczo to, co muszę zrobić. –

+0

Naprawdę nie rozumiem, w jaki sposób odpowiedź została przyjęta. Jak po pierwszym kliknięciu wyłączyć, jeśli zdarzenie zostało zmodyfikowane jako asynchroniczne? I inne; proces synchronizacji nie zapobiega również dwukrotnemu kliknięciu. –

+0

Ta odpowiedź nie jest poprawna, ponieważ zdarzenie jest asynchroniczne. – TeoVr81

3

Można ustawić flagę

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

Dodałbym try {boolClicked = true; Zrób coś(); } Na koniec {boolClicked = false;}, aby upewnić się, że zresetowałeś flagę. Twoje zdrowie. – SRO

+0

@nathan koop nie próbował przetestować kodu w prawdziwej aplikacji Xamarin Forms. –

0

Jeśli kontrola wywodzi System.Windows.Forms.Control, można użyć double click event.

Jeśli to nie wynika z System.Windows.Forms.Control, następnie wire up mousedown zamiast i potwierdzić kliknięciem count == 2:

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

To jest formant WPF ... Pochodzi z System.Windows.Controls.Control –

+0

Następnie można użyć tego: http://msdn.microsoft.com/en-us/library/system.windows.input. mousebuttoneventargs.clickcount.aspx A może przegapiłem? –

+0

Celem nie było zajęcie się zdarzeniem z podwójnym kliknięciem; moim zamiarem jest stłumienie tego. –

3

Zakładając, że WPF dowódca nie daje wystarczającą kontrolę pomieszać z modułem obsługi kliknięć, czy możesz umieścić kod w procedurze obsługi komend, który pamięta ostatnie wykonanie polecenia i kończy działanie, jeśli zostanie zażądany w określonym czasie? (przykładowy kod poniżej)

Chodzi o to, że jeśli to dwukrotne kliknięcie, otrzymasz zdarzenie dwa razy w ciągu milisekund, więc zignoruj ​​drugie zdarzenie.

coś takiego: (wewnątrz 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 
} 
 

(uwaga: jeśli to był tylko zwykły stary click obsługi, powiedziałbym tego zalecenia: http://blogs.msdn.com/oldnewthing/archive/2009/04/29/9574643.aspx)

+0

Dobry link. Technika odsłonięcia, o której wspominasz, jest dokładnie tym, o czym mówię. Wyłącza czasami nasze błędy w działaniu programu WPF, jeśli dwukrotnie klikniesz przyciski, które mają być klikane pojedynczo. –

-2

Sprawdza jeśli sprawdzanie poprawności minęło, a jeśli tak, to wyłącza przycisk.

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. Nie jestem pewien, co się tutaj dzieje, ale wygląda na to, że zakładasz ASP.NET lub coś podobnego. Nie ma strony, klienta Client ani postu. –

+0

Tak, złe miejsce do publikowania tego. To jest dla standardowego asp.net, a nie wpf. – ta4ka

3

Można użyć klasy EventToCommand w MVVMLightToolkit aby temu zapobiec.

Obsługa zdarzenia Click i wysłanie go przez EventToCommand z widoku do widoku (można użyć do tego celu EventTrigger).
Ustaw MustToggleIsEnabled="True" w widoku i zaimplementuj metodę CanExecute() w swoim widoku modelu.
Ustaw CanExecute(), aby zwrócić wartość false, gdy polecenie zostanie uruchomione i powróci do wartości true, gdy polecenie zostanie wykonane.

Spowoduje to wyłączenie przycisku na czas przetwarzania polecenia.

+1

Mięso, o którym mówisz: Jeśli przycisk jest powiązany z poleceniem, wyłącz polecenie (CanExecute() = false), dopóki polecenie nie zostanie wykonane. –

+0

@Josh G: tak, rzeczywiście! – stombeur

7

miałem ten sam problem i to pracował dla mnie:

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

Wow. Jeśli to zadziała, byłoby fantastycznie. Będę musiał kiedyś to wypróbować. –

+0

Mogę potwierdzić, że to zadziałało także dla mnie, dzięki! – Simone

+0

Poważnie, jak to znalazłeś? – Snake

4

Można by pomyśleć, że to będzie tak proste, jak przy użyciu Command i podejmowania CanExecute() return false, gdy polecenie jest uruchomiony. Byłbyś w błędzie. Nawet jeśli podnieść CanExecuteChanged wyraźnie:

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

Podejrzewam, że jeśli ta komenda miała odniesienie do okna na Dispatcher i wykorzystywane Invoke gdy nazywa OnCanExecuteChanged, że to działa.

Potrafię wymyślić kilka sposobów rozwiązania tego problemu. Podejście JMarscha: po prostu śledź, gdy jest wywoływana Execute, i wyskocz bez niczego, jeśli zostało wywołane w ciągu ostatnich kilkuset milisekund.

Bardziej wytrzymałe sposób może być mieć metoda Execute rozpocząć BackgroundWorker zrobić rzeczywiste przetwarzanie mieć CanExecute zwrot (!BackgroundWorker.IsBusy) i podniesienie CanExecuteChanged w kiedy zadanie zostanie zakończone. Przycisk powinien zażądać CanExecute() od razu po powrocie Execute(), co zrobi natychmiast.

+0

Wydaje mi się, że nie wypróbowałeś wielu kliknięć (na tyle szybko), kiedy go testujesz. To nie działa ... –

14

Sprawdzona odpowiedź na to pytanie, przesłana przez vidalsasoon, jest błędna i błędna na wszystkie różne sposoby zadawania tego samego pytania.

Jest możliwe, że każda procedura obsługi zdarzenia zawierająca kod wymagający znacznego czasu przetwarzania może spowodować opóźnienie wyłączenia danego przycisku; niezależnie od miejsca, w którym wywoływana jest linia kodu w obrębie programu obsługi.

Wypróbuj poniższe dowody, a zobaczysz, że wyłączenie/włączenie nie ma związku z rejestracją zdarzeń. Zdarzenie click button jest nadal rejestrowane i nadal jest obsługiwane.

dowód nie wprost 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; 

} 

dowodu, 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

OP używa MVVM (binding) i Commands for WPF. Używasz "zdarzeń" WinForms, które tutaj nie mają zastosowania. – vidalsasoon

+1

@vidalsasoon Masz rację, że użyłem WinForm jako demonstracji. Kluczową kwestią jest jednak to, że rejestracja zdarzeń jest odizolowana od innych przycisków/przycisków włączania lub wyłączania właściwości, a wyłączenie przycisku nie uniemożliwia zasubskrybowanemu modułowi obsługi zdarzenia wykonania kodu. Dotyczy to WPF i WinForm. Po prostu starałem się wskazać, że sprawdzona odpowiedź w tym poście jest nieprawidłowa. Bez zamiaru zamierzonego. Sam popełniłem błąd. – JDennis

5

prosty & Skuteczna blokowania podwójne, potrójne i poczwórne kliknięcia

<Button PreviewMouseDown="Button_PreviewMouseDown"/> 

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

Rozwiązaliśmy to tak ... z async nie mogliśmy znaleźć żadnego innego sposobu, aby skutecznie blokować dodatkowe kliknięcia przycisku, który wywołuje tę kliknij:

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

Proste i eleganckie rozwiązanie jest stworzenie Zachowanie wyłączanie reakcji po drugim kliknięciu w scenariusz dwukrotnego kliknięcia. To dość proste w użyciu:

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

zachowanie (więcej o zachowania - 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

miał ten sam problem, rozwiązać go za pomocą załączonego zachowanie.

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

    } 
} 

a potem po prostu ustawić właściwość PRAWDA bezpośrednio w XAML deklarując styl, dzięki czemu wpływa na wszystkie przyciski na raz. (nie zapomnij o deklaracji przestrzeni nazw XAML)

<Style x:Key="styleBoutonPuff" TargetType="{x:Type Button}"> 
    <Setter Property="VLEvaControls:ButtonBehavior.IgnoreDoubleClick" Value="True" /> 
    <Setter Property="Cursor" Value="Hand" /> 
</Style> 
Powiązane problemy