【问题标题】:Is it possible the WPF events to be added to the queue for execution in sequence?是否可以将 WPF 事件添加到队列中以按顺序执行?
【发布时间】:2020-09-03 12:31:33
【问题描述】:

如果我在窗口中添加一个按钮并处理其单击异步事件的过程很长,那么即使该按钮正在进行中,也可以多次单击该按钮。它将事件保留在队列中并按顺序执行。

 private async void Button_Click(object sender, RoutedEventArgs e)
    {
        await Task.Delay(2000);
        Console.WriteLine("Button 1 ends");
    }

问题:是否有可能以事件的同步形式获得这样的结果?

 private void Button_Click(object sender, RoutedEventArgs e)
    {
        for (int i = 0; i < 10000000; i++)
        {

        }
        Console.WriteLine("Button 1 ends");
    }

我们希望在用户尝试时防止多次点击。如果系统冻结或出现问题,用户可以多次单击,但我们希望防止这种情况发生。

【问题讨论】:

  • 简单的方法是禁用按钮如果您希望用户在现有方法调用正在进行时阻止单击按钮,
  • 不,这是最具欺骗性的做法。因为,正如我上面提到的,如果程序卡住或出现问题,可以在这些预防措施之前多次单击(禁用元素,使用另一个 bool 变量等)。我想找到一种更准确的方法来做到这一点。
  • 在点击事件处理程序的第一行使用((Button)sender).IsEnabled = false。祝你好运,点击两次。
  • 当您正确处理异常并禁用按钮时,您如何能够多次单击?

标签: c# wpf events


【解决方案1】:

编辑:抱歉,我最初误解了这个问题,认为要求是对点击进行排队并防止多个同时执行。这是更新

private async void Button_Click(object sender, RoutedEventArgs e)
{
    var button = (Button)sender;
    button.IsEnabled = false;
    try
    {
        // Perform long task here
        
    }
    finally
    {
        button.IsEnabled = true;
    }
}

【讨论】:

  • 执行 _semaphore.Release();意味着处置(); ?它是用那个命令处理的吗?
  • 我不认为信号量会阻止再次点击按钮,它只会阻止“长任务”在它已经运行时执行。 Windows 仍会将点击排队并在信号量释放后执行。
  • 这个问题根本不需要锁定机制。任何类型的锁定机制都是为了避免竞争条件。
  • Release()Dispose() 不同。 Release() 会将当前可用计数增加 1。Dispose() 将丢弃该对象,您不能再次使用它。
  • 信号量基本上是限制有多少线程可以访问一段代码。标有异步的多个按钮单击不会创建任何线程。异步是一种状态机模式,基本上处理代码执行的控制流。只有 Task 会创建线程。要求是只处理多次 UI 点击
【解决方案2】:

为什么不在信号量中使用标志?

// Initialize the Semaphore to initial and max count of 1
    private readonly SemaphoreSlim _semaphore = new SemaphoreSlim(1, 1);
    private bool alreadyExecuted = false;
    private async void Button_Click(object sender, RoutedEventArgs e)
    {
        var tmp = await functionToCall();
    }

    private async Task<bool> functionToCall()
    {
        // Wait for semaphone to have an available slot
        await _semaphore.WaitAsync();

        try
        {
            if (!alreadyExecuted)
            {

                // Perform long task here
                // Only one handler can be here at a time. You can increase this by increasing max count and initial count of the semaphore in the constructor.
            }
        }
        finally
        {
            alreadyExecuted = true;

            // Release the lock in a finally block to ensure it is released even in case of an error
            _semaphore.Release();
        }
        return alreadyExecuted;
    }

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 2013-02-11
    • 1970-01-01
    • 1970-01-01
    • 2013-09-26
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多