【问题标题】:button queues its click events instead of disabling it按钮将其单击事件排队而不是禁用它
【发布时间】:2019-02-19 12:18:21
【问题描述】:

我将按钮的“Enabledproperty 更改为“false”,但我的按钮仍然捕捉到它的点击事件。我把 Thread.Sleep() 方法用来模拟一些过程。当我的按钮变灰时,我点击它,在当前进程完成后它再次开始工作(因为我在它变灰时点击了它)

这是我的代码:

    int i = 0;

    public Form1()
    {
        InitializeComponent();
        label1.Text = "0";
    }

    private void button1_Click(object sender, EventArgs e)
    {
        //first click
        button1.Enabled = false;
        i++;
        Thread.Sleep(3000);           //if i click twice more while button is greyed-out the app will be non-responsive for 9 second and then prints "3" to my label
        label1.Text = i.ToString();
        button1.Enabled = true;
    }

我怎样才能完全禁用我的按钮(不允许它的事件上升,但可见)?

【问题讨论】:

  • 每次单击按钮时,UI 线程都会冻结 3 秒。
  • 您试图在其单击事件中禁用该按钮,此时您的事件已经引发。您应该尝试在 Form1 ctor 中禁用它。

标签: c# .net winforms events button


【解决方案1】:

您正在冻结 UI 线程,这会阻止任何事情发生在 UI 方面。您应该考虑使用 TPL 来完成此类工作。

private async void button1_Click(object sender, EventArgs e)
{
    //first click
    button1.Enabled = false;

    i++;

    await Task.Delay(TimeSpan.FromSeconds(3));

    label1.Text = i.ToString();
    button1.Enabled = true;
}

【讨论】:

  • 这行得通,谢谢!对不起,如果这是个愚蠢的问题,但如果我的 UI 冻结,它是如何感知我的点击的?
  • @HüseyinMerkit 有很多资源可以解释 UI 线程背后的概念。简而言之,控件上的所有交互(点击等)都由一个专用线程管理。例如,当您单击按钮时,会在该线程上调用 button1_click 方法。但是如果你阻塞这个线程,就像你在方法中使用 Thread.Sleep 一样,应用程序将无法处理任何其他输入,直到线程被解除阻塞。
【解决方案2】:

Thread.Sleep(3000) 调用阻塞了该函数,因此按钮不会被禁用。一个快速而肮脏的解决方法是在button1.Enabled = false; 之后直接调用Application.DoEvents();。这会强制应用程序处理任何等待事件,并应确保该按钮被禁用。

如果您打算用长时间运行的进程替换 Thread.Sleep(3000),那么您应该使用 BackgroundWorker。您可以在设计器工具箱的组件下找到它。

【讨论】:

    猜你喜欢
    • 2015-03-28
    • 2016-03-20
    • 1970-01-01
    • 1970-01-01
    • 2012-06-02
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2012-05-20
    相关资源
    最近更新 更多