Prevent double-click from double firing a command

前端 未结 14 1690
情书的邮戳
情书的邮戳 2020-12-15 08:34

Given that you have a control that fires a command:

Is there a way to prevent the command from being fired

相关标签:
14条回答
  • 2020-12-15 09:27

    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.

    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

    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

    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 讨论(0)
  • 2020-12-15 09:29

    I'm using Xamarin and MVVMCross, although is not WPF I think the following solution applies, I created a solution which is viewmodel specific (doesn't deal with platform specific UI) which I think is very handy, using a helper or base class for the viewmodel create a List that keeps track of the commands, something like this:

    private readonly List<string> Commands = new List<string>();
    
            public bool IsCommandRunning(string command)
            {
                return Commands.Any(c => c == command);
            }
    
            public void StartCommand(string command)
            {
                if (!Commands.Any(c => c == command)) Commands.Add(command);
            }
    
            public void FinishCommand(string command)
            {
                if (Commands.Any(c => c == command))  Commands.Remove(command);
            }
    
            public void RemoveAllCommands()
            {
                Commands.Clear();
            }
    

    Add the command in the action like this:

    public IMvxCommand MyCommand
            {
                get
                {
                    return new MvxCommand(async() =>
                    {
                        var command = nameof(MyCommand);
                        if (IsCommandRunning(command)) return;
    
                        try
                        {
                            StartCommand(command);
    
                            await Task.Delay(3000);
                           //click the button several times while delay
                        }
                        finally
                        {
                            FinishCommand(command);
                        }
                    });
                }
            }
    

    The try/finally just ensures the command is always finished.

    Tested it by setting the action async and doing a delay, first tap works second one returns in the condition.

    0 讨论(0)
提交回复
热议问题