示例代码
using System;
using System.Threading;
using System.Windows.Forms;
namespace ClickDemo
{
public partial class Form1 : Form
{
private string text = "";
public Form1()
{
InitializeComponent();
}
private void button_Click(object sender, EventArgs e)
{
print(1,true);
setEnable(false);
print(2);
Thread.Sleep(2000);
print(3);
setEnable(true);
print(4);
}
private void setEnable(bool enable)
{
this.button.Enabled = enable;
}
private void print(int num,bool isPrint = false)
{
if (isPrint)
{
text += "\r\n---------------------------------";
}
text += $"\r\n{DateTime.Now} button state{num}: {this.button.Enabled}";
this.textBox.Text = text;
}
private void btnClear_Click(object sender, EventArgs e)
{
text = "";
this.textBox.Text = text;
setEnable(true);
}
}
}
大家从button_Click
事件中应该明白笔者所想要验证的内容,不错,就是在进入Click事件的时候让这个按键不可点击,但是上面的实现貌似不能解决问题。
运行效果
结果分析
以上的结果是笔者连续点击button
后的运行结果,明明是想只运行一次,为什么触发了这么多次,从输出的log上来看明显是正常的啊。难道button设置Enabled=False后还可以点击不成,其实不是,事实上它根本没有上来就执行 setEnable(false),看最后一句log,为什么不是紧跟着状态变为False
的呢。大家可以实际演示一下,代码就在上面,从打印的内容上可以发现,它是在耗时操作执行完以后才设置的False
。
这是因为消息机制引起的问题,如果处理click事件的函数执行时间过长,那么下一次点击的消息会存入消息队列,等到当前click处理函数退出以后,再从消息队列获取此消息执行。你可以使用笔者提供的代码,多次点击button,你会看到多次的重复执行。
解决此问题可以使用异步调用等完成后回调。
解决方法
将button_Click
事件内容改成如下所示
private void button_Click(object sender, EventArgs e)
{
print(1, true);
setEnable(false);
print(2);
new Thread(() =>
{
Thread.Sleep(2000);
this.BeginInvoke(new Action(() =>
{
print(3);
setEnable(true);
print(4);
}));
}).Start();
}
再次多次点击按钮,运行的效果就和期望的一致了。