C# 防止双击双击命令

声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow 原文地址: http://stackoverflow.com/questions/841332/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me): StackOverFlow

提示:将鼠标放在中文语句上可以显示对应的英文。显示中英文
时间:2020-08-05 03:45:15  来源:igfitidea点击:

Prevent double-click from double firing a command

c#.netwpfdouble-click

提问by Josh G

Given that you have a control that fires a command:

鉴于您有一个触发命令的控件:

<Button Command="New"/>

Is there a way to prevent the command from being fired twice if the user double clicks on the command?

如果用户双击命令,有没有办法防止命令被触发两次?

EDIT:What is significant in this case is that I am using the Commandingmodel in WPF.

编辑:在这种情况下,重要的是我在 WPF 中使用命令模型。

It appears that whenever the button is pressed, the command is executed. I do not see any way of preventing this besides disabling or hiding the button.

似乎只要按下按钮,就会执行命令。除了禁用或隐藏按钮之外,我看不出有任何方法可以防止这种情况发生。

回答by Nathan Koop

You could set a flag

你可以设置一个标志

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

回答by Noel Kennedy

If your control derives from System.Windows.Forms.Control, you can use the double click event.

如果您的控件派生自 System.Windows.Forms.Control,则可以使用双击事件

If it doesn't derive from System.Windows.Forms.Control, then wire up mousedowninstead and confirm the click count == 2 :

如果它不是从 System.Windows.Forms.Control 派生的,则改为连接 mousedown并确认 click count == 2 :

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

回答by JMarsch

Assuming that WPF Commanding doesn't give you enough control to mess with the click handler, could you put some code in the command handler that remembers the last time the command was executed and exits if it is requested within a given time period? (code example below)

假设 WPF Commanding 没有给您足够的控制权来干扰单击处理程序,您能否在命令处理程序中放置一些代码来记住上次执行命令的时间并在给定时间段内请求时退出?(下面的代码示例)

The idea is that if it's a double-click, you'll receive the event twice within milliseconds, so ignore the second event.

这个想法是,如果是双击,您将在几毫秒内收到该事件两次,因此忽略第二个事件。

Something like: (inside of the 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
}

(note: if it were just a plain old click handler, I'd say follow this advice: http://blogs.msdn.com/oldnewthing/archive/2009/04/29/9574643.aspx)

(注意:如果它只是一个普通的旧点击处理程序,我会说遵循以下建议:http: //blogs.msdn.com/oldnewthing/archive/2009/04/29/9574643.aspx

回答by ta4ka

This checks if validation has passed and if it does then disables the button.

这会检查验证是否通过,如果通过则禁用按钮。

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

回答by stombeur

You can use the EventToCommandclass in the MVVMLightToolkitto prevent this.

您可以使用MVVMLightToolkit 中EventToCommand类来防止这种情况。

Handle the Click event and send it through EventToCommandfrom your view to your viewmodel (you can use EventTriggerto do this).
Set MustToggleIsEnabled="True"in your view and implement a CanExecute()method in your viewmodel.
Set CanExecute()to return false when the command starts to execute and back to true when the command is done.

处理 Click 事件并将其EventToCommand从您的视图发送到您的视图模型(您可以使用它EventTrigger来执行此操作)。在您的视图中
设置并MustToggleIsEnabled="True"在您的视图模型中实现一个CanExecute()方法。
设置CanExecute()为在命令开始执行时返回 false,并在命令完成时返回 true。

This will disable the button for the duration of processing the command.

这将在处理命令期间禁用该按钮。

回答by Oleksandr Lytvyn

I had the same issue and this worked for me:

我有同样的问题,这对我有用:

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

回答by Robert Rossney

You'd think that it would be as simple as using a Commandand making CanExecute()return false while the command is running. You would be wrong. Even if you raise CanExecuteChangedexplicitly:

您会认为这就像在命令运行时使用 aCommandCanExecute()返回 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;
}

I suspect that if this command had a reference to the window's Dispatcher, and used Invokewhen it called OnCanExecuteChanged, it would work.

我怀疑如果这个命令引用了窗口的Dispatcher,并Invoke在调用时使用OnCanExecuteChanged,它会起作用。

I can think of a couple of ways to solve this problem. One's JMarsch's approach: simply track when Executeis called, and bail out without doing anything if it was called in the last few hundred milliseconds.

我可以想到几种方法来解决这个问题。JMarsch 的方法是:简单地跟踪何时Execute被调用,如果在最后几百毫秒内被调用,则不做任何事情就退出。

A more robust way might be to have the Executemethod start a BackgroundWorkerto do the actual processing, have CanExecutereturn (!BackgroundWorker.IsBusy), and raise CanExecuteChangedin when the task is complete. The button should requery CanExecute()as soon as Execute()returns, which it'll do instantly.

更健壮的方法可能是让Execute方法 start aBackgroundWorker进行实际处理,CanExecute返回(!BackgroundWorker.IsBusy)CanExecuteChanged在任务完成时提升。该按钮应CanExecute()Execute()返回后立即重新查询,它会立即执行。

回答by JDennis

The checked answer to this question, submitted by vidalsasoon, is wrong and it is wrong for all of the various ways this same question has been asked.

由 vidalsasoon 提交的对这个问题的检查答案是错误的,并且对于同一个问题的所有提出方式都是错误的。

It is possible that any event handler that contains code that requires a significant process time, can result in a delay to the disabling of the button at question; regardless to where the disabling line of code is called within the handler.

任何包含需要大量处理时间的代码的事件处理程序都有可能导致禁用相关按钮的延迟;无论在处理程序中调用禁用代码行的位置。

Try the proofs below and you will see that disable/enable has no correlation to the registration of events. The button click event is still registered and is still handled.

试试下面的证明,你会看到禁用/启用与事件注册没有关联。按钮点击事件仍然被注册并且仍然被处理。

Proof by Contradiction 1

矛盾证明 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;

}

Proof by Contradition 2

矛盾证明 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();
}

回答by Jon Dosmann

Simple & Effective for blocking double, triple, and quadruple clicks

简单有效地阻止两次、三次和四次点击

<Button PreviewMouseDown="Button_PreviewMouseDown"/>

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

回答by John Fairbanks

We solved it like this... with async we couldn't find any other way to effectively block extra clicks on the button which invokes this Click:

我们是这样解决的......使用异步我们找不到任何其他方法来有效阻止调用此 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;
        }
    }
}