2009-05-08 1 views
9

Учитывая, что у вас есть контроль, который стреляет команду:Предотвращение двойного щелчка от двойного обжига команды

<Button Command="New"/> 

Есть ли способ, чтобы предотвратить команду от увольнения в два раз, если пользователь дважды щелкает по команде ?

EDIT: В этом случае важно то, что я использую модель Commanding в WPF.

Кажется, что всякий раз, когда нажимается кнопка, выполняется команда. Я не вижу никакого способа предотвратить это, кроме отключения или скрытия кнопки.

+0

Нет похожего на то, чтобы настроить/переопределить внутреннюю обработку WPF события click? –

ответ

1

Возможно, кнопка должна быть отключена после первого нажатия и до завершения обработки?

+0

Я считаю, что это по существу то, что мне нужно будет сделать. –

+0

Я действительно не понимаю, как был принят ответ. Как после первого щелчка следует отключить, если событие изменено как async? И другие; Синхронизация не препятствует двойному щелчку. –

+0

Этот ответ неверен, поскольку событие равно асинхронному. – TeoVr81

3

Вы можете установить флаг

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

Я бы добавил Try {boolClicked = true; Сделай что-нибудь(); } Наконец, {boolClicked = false;}, чтобы сбросить флаг. Приветствия. – SRO

+0

@nathan koop не пытался проверить ваш код на реальном приложении Xamarin Forms. –

0

Если элемент управления происходит от System.Windows.Forms.Control, вы можете использовать double click event.

Если не вытекает из System.Windows.Forms.Control, то wire up mousedown вместо этого и подтверждения счета нажмите == 2:

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

Это элемент управления WPF ... Он происходит из System.Windows.Controls.Control –

+0

Затем вы можете использовать это: http://msdn.microsoft.com/en-us/library/system.windows.input. mousebuttoneventargs.clickcount.aspx Или я пропустил понимание? –

+0

Целью было не обрабатывать событие двойного щелчка; мое намерение - подавить его. –

3

Предполагая, что WPF Commanding не дает достаточного контроля для беспорядок с обработчиком кликов, можете ли вы поместить некоторый код в обработчик команд, который помнит последний раз, когда команда была выполнена и завершена, если она запрашивается в течение заданного периода времени? (пример кода ниже)

Идея состоит в том, что если это двойной щелчок, вы получите событие дважды в миллисекундах, поэтому проигнорируйте второе событие.

Что-то вроде: (внутри 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 
} 
 

(примечание: если бы это было просто обычный старый обработчик щелчка, я бы сказал, что этот совет: http://blogs.msdn.com/oldnewthing/archive/2009/04/29/9574643.aspx)

+0

Хорошая ссылка. Техника абзаца, о которой вы говорите, именно то, о чем я говорю. Оказалось, что наша программа WPF ошибочна, если вы дважды щелкаете по кнопкам, которые были предназначены для однократного нажатия. –

-2

Проверяется если проверка прошла, и если это произойдет, отключит кнопку.

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

Ничего себе. Не уверен, что здесь происходит, но похоже, что вы принимаете ASP.NET или что-то в этом роде. Нет ни страницы, ни ClientScript, ни обратной записи. –

+0

Да, неправильное место, чтобы опубликовать это. Это для стандартного asp.net, а не для wpf. – ta4ka

3

Вы можете использовать EventToCommand класс в MVVMLightToolkit, чтобы предотвратить это.

Обращайтесь к событию Click и отправьте его по адресу EventToCommand с вашего вида на ваш режим просмотра (вы можете использовать EventTrigger для этого).
MustToggleIsEnabled="True" на ваш взгляд и реализовать метод CanExecute() в вашей модели.
Установите CanExecute(), чтобы вернуть значение false, когда команда начнет выполнение и вернется к истине, когда команда выполнена.

Это отключит кнопку на время обработки команды.

+1

Мясо того, что вы говорите: если кнопка привязана к команде, отключите команду (CanExecute() = false), пока команда не завершит обработку. –

+0

@ Josh G: Да, действительно! – stombeur

7

Я была такая же проблема, и это работает для меня:

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

Ничего себе. Если это сработает, это будет фантастично. Мне придется попробовать это когда-нибудь. –

+0

Я могу подтвердить, что это сработало и для меня, спасибо! – Simone

+0

Серьезно, как вы это нашли? – Snake

4

Можно подумать, что было бы так просто, как с помощью Command и делает CanExecute() возвращение ложным в то время как команда работает. Вы ошибаетесь. Даже если вы поднимаете 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, он будет работать.

Я могу придумать пару способов решить эту проблему. Один подход JMarsch: просто отслеживайте, когда вызывается Execute, и выручайте, не делая ничего, если он был вызван за последние несколько сотен миллисекунд.

Более надежный способ может быть, чтобы иметь метод Execute начать BackgroundWorker делать фактическую обработку, имеет CanExecute возвращения (!BackgroundWorker.IsBusy) и поднять CanExecuteChanged в том, когда задача будет завершена. Кнопка должна запросить CanExecute(), как только Execute() вернется, что будет сделано мгновенно.

+0

Я думаю, что вы не пробовали много кранов (достаточно быстро), когда вы его тестируете. Он не работает ... –

14

Проверенный ответ на этот вопрос, представленный vidalsasoon, является неправильным, и это неверно для всех различных способов, заданных этим же вопросом.

Возможно, что любой обработчик событий, содержащий код, требующий значительного времени процесса, может привести к задержке отключения кнопки на вопрос; независимо от того, где вызывающая строка кода вызывается внутри обработчика.

Попробуйте приведенные ниже доказательства, и вы увидите, что функция disable/enable не имеет отношения к регистрации событий. Событие нажатия кнопки по-прежнему регистрируется и все еще обрабатывается.

Доказательство от противного 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(); 
} 
+0

OP использует MVVM (привязка) и команды для WPF. Вы используете метод «событий» WinForms, который здесь не применяется. – vidalsasoon

+1

@vidalsasoon Вы правы, что я использовал Winforms в качестве демонстрации. Однако ключевой момент состоит в том, что регистрация событий изолирована от других элементов управления/кнопок, которые позволяют включать или отключать свойство и отключать кнопку, не препятствуют выполнению кода обработчиком подписанного события. Это справедливо для WPF и Winforms. Я просто пытался указать, что проверенный ответ на этот пост неверен. Никакое преступление не предназначено. Я сам совершил ошибку. – JDennis

5

Простой & эффективный для блокировки двойной, тройной и четверной щелчков

<Button PreviewMouseDown="Button_PreviewMouseDown"/> 

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

Мы ее решили, как это ... с асинхронным мы не смогли найти какой-либо другой способ эффективно блокировать лишние клики по кнопке, которая вызывает этот щелчок:

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

Простое и элегантное решение заключается в создании поведения отключение реакции при втором щелчке в сценарии двойного щелчка. Это очень проста в использовании:

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

была такая же проблема, решить ее, используя прилагаемую поведение.

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

    } 
} 

, а затем просто установить свойство TRUE, либо непосредственно в XAML, объявив стиль, поэтому он может влияет на все кнопки сразу. (не забудьте прописку пространства имен XAML)

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