C# Winform 事件阻止问题

wyb0026 2012-07-06 11:34:30
private void button1_Click(object sender, EventArgs e)
{
i++;
Thread.Sleep(2000);
button1.Text = i.ToString();
}

第一次按下时UI不可用两秒钟,但是在两秒钟内再按钮时候,后按得也将被执行
我想在UI不可用过程中后续事件不响应,怎样写

现在这种情况出现了重复提交

private void button1_Click(object sender, EventArgs e)
{
button1.Enabled = false;
i++;
Thread.Sleep(2000);
button1.Text = i.ToString();
button1.Enabled = true;
}
也不好用
...全文
1680 28 打赏 收藏 转发到动态 举报
写回复
用AI写文章
28 条回复
切换为时间正序
请发表友善的回复…
发表回复
g394594141 2014-06-20
  • 打赏
  • 举报
回复
意思用17楼代码已经可以了吗? 如果还不行,试试下面三个函数呢 this.SuspendLayout(); this.ResumeLayout(false); this.PerformLayout(); 这三个函数或许对你有帮助。 申明:我没有测试过
liuyuaihaili 2012-07-12
  • 打赏
  • 举报
回复
Application.DoEvent()最好不要使用,要实现你说的效果可以试一下win32 api peekmessage把消息队列中的鼠标点击事件去掉
ParanoidKing 2012-07-06
  • 打赏
  • 举报
回复
这个问题的关键在于,由于是UI线程去处理事务,这时候去点击按钮,消息会一直在Windows的消息队列中等待,直到UI线程空闲时再去引发Click事件。所以这种情况下不管在Click事件中判断标志量还是解除事件注册,都没有用,因为再次进来到这里时标志量或者事件都已经还原了。
所以要解决这个问题,要么在事件处理结束前把Windows消息队列中按钮的单击消息清除掉,要么用多线程去处理事务,让UI线程立即返回,以响应下一个Click消息,这时就可以通过标志量或者事件去控制按钮是否响应事件了。第一种方案没研究过,第二种就简单多了。

private void button1_Click(object sender, EventArgs e)
{
if (button1.Enabled)
{
button1.Enabled = false;
Thread t = new Thread(() =>
{
i++;
Thread.Sleep(2000);
button1.Invoke(new Action(() =>
{
button1.Text = i.ToString();
button1.Enabled = true;
}));
});
t.IsBackground = true;
t.Start();
}
}
SocketUpEx 2012-07-06
  • 打赏
  • 举报
回复
上面是从技术方面来说
下面从产品方面来说:
按钮不给点,就应该设置成Enabled = false
如果Enabled = true,用户点了又没反应,难免会有用户抱怨了:
Y的,什么意思啊,Enabled = true,点了又没反应,是不是bug啊
SocketUpEx 2012-07-06
  • 打赏
  • 举报
回复
虽然-= += 很优雅
但按楼主的要求,不是很赞成使用
-= +=内部要处理的操作绝对比Enabled属性,或者标志量要多
还是使用Enabled属性或者标志量来处理吧
qldsrx 2012-07-06
  • 打赏
  • 举报
回复
其实你那个是因为界面没来得及响应那个Enabled改变事件造成的,可以在Enabled改变后加入
Application.DoEvent();

这样做肯定没问题,不过最好的做法是取消事件,写法如下:
private void button1_Click(object sender, EventArgs e)
{
button1.Click -= button1_Click;
i++;
Thread.Sleep(2000);
button1.Text = i.ToString();
//注意,如果代码执行过程可能有异常发生,
//必须用try-finally语句,
//并将此行代码加入到finally中执行
button1.Click += button1_Click;
}
wyb0026 2012-07-06
  • 打赏
  • 举报
回复
[Quote=引用 5 楼 的回复:]

如果单线程, 第一个事件没结束后,根本不会执行第二次点击
[/Quote]

第一个没结束第二个是没有执行,但是一执行后,紧跟着2,3就执行了
我希望的是,一没有结束之前,怎么按按钮都不好用,不会发生2,3。。。
mizuho_2006 2012-07-06
  • 打赏
  • 举报
回复
也可以这么用吧
private void button1_Click(object sender, EventArgs e)
{
if(button1.Enabled)
{
button1.Enabled = false;
i++;
Thread.Sleep(2000);
button1.Text = i.ToString();
button1.Enabled = true;
}
}
honkerhero 2012-07-06
  • 打赏
  • 举报
回复
如果单线程, 第一个事件没结束后,根本不会执行第二次点击
SocketUpEx 2012-07-06
  • 打赏
  • 举报
回复
button1.Enabled = false;
button1.Enabled = true;

说说为什么不好用
mizuho_2006 2012-07-06
  • 打赏
  • 举报
回复
bool IsPress = false;
private void button1_Click(object sender, EventArgs e)
{
if(!IsPress)
{
IsPress = true;
i++;
Thread.Sleep(2000);
button1.Text = i.ToString();
IsPress = false;
}
}

wyb0026 2012-07-06
  • 打赏
  • 举报
回复
在一个事件没结束之前,Click事件再不响应
Kogeo_Guan 2012-07-06
  • 打赏
  • 举报
回复
什么叫事件阻止呢?
wyb0026 2012-07-06
  • 打赏
  • 举报
回复
谢谢了,结贴去研究研究
qldsrx 2012-07-06
  • 打赏
  • 举报
回复
MSDN上有Application.DoEvents()的详细介绍,这里是用来处理WINDOWS消息响应的,在Application.DoEvents()的插入点,所有排队等待的WINDOWS消息都会依次响应(例如改变控件属性要体现在界面上,点击按钮要触发按钮的点击事件等)后,再执行后续代码。
qldsrx 2012-07-06
  • 打赏
  • 举报
回复
[Quote=引用 21 楼 的回复:]
我是没有搞懂Application.DoEvents()的用法,但是不用,还是不好用,所以我就加了。真正原因谁能指导一下
[/Quote]
我特意模拟了下按钮的连点(实际谁吃饱了没事去连点啊)。
发现这个事件有个排队等待的过程,也就是说,当设置了Enable为false后,立刻禁止按钮的点击,但是这个过程还是没你连点速度快的话,还是会至少执行了2次事件,而你在事件执行后(延迟2秒后)再执行Application.DoEvents(),意味着提前响应那个鼠标点击事件(如果不调用则会在全部执行后响应),这个响应时间点很重要,因为在Application.DoEvents()插入点响应的话,由于此刻已经取消了事件处理函数,所以将无任何动作,你不添加Application.DoEvents(),变成了执行结束后才响应点击事件,这个时候事件又被重新加载了。
如果你对执行次数有严格控制,不允许执行2次(一般2次以上执行是没啥关系的),最好判断下那个变量i的值,代码如下:
        private void button1_Click(object sender, EventArgs e)
{
if (i == 0)
{
i++;
Thread.Sleep(2000);
button1.Text = i.ToString();
}
}

当然你设置bool类型的变量用于判断也足够。
我感觉这样会更好些,不然即使用户在你点击按钮执行过程中没有多次点击,按钮执行过程结束后再去点击呢?你还得控制的话,肯定要用变量来记录是否点击过了。
猴头 2012-07-06
  • 打赏
  • 举报
回复
谁能详细的解释下Application.DoEvents()用法?
wyb0026 2012-07-06
  • 打赏
  • 举报
回复
我是没有搞懂Application.DoEvents()的用法,但是不用,还是不好用,所以我就加了。真正原因谁能指导一下
qldsrx 2012-07-06
  • 打赏
  • 举报
回复
被你这么一说,的确他加了Application.DoEvents();,因为这行代码一般都紧跟着“阻止代码”如Enable改变或-=取消事件之后的,所以我只看了前面两行代码,没看下去。这说明楼主根本没搞懂Application.DoEvents();的作用,滥用它,他那个地方根本不需要添加的,建议你自己实际编写代码测试下,我所说的自己写过很多代码在实际项目中了,肯定没错的。
SocketUpEx 2012-07-06
  • 打赏
  • 举报
回复
[Quote=引用 18 楼 的回复:]
我什么时候说过要在-=操作后调用Application.DoEvent()的?你看过#12楼的代码没有
[/Quote]

你真的没说过-=后要调用Application.DoEvent(),而且8楼一步到位的代码还特意去掉了Application.DoEvent()
然后
我不但看了三遍12楼的代码,两份代码里确实都有Application.DoEvent()
还亲自测试了,得出的结论就是:
你的一步到位的代码,也和Enabled=false一样需要Application.DoEvent()才能一步到位
加载更多回复(7)

110,538

社区成员

发帖
与我相关
我的任务
社区描述
.NET技术 C#
社区管理员
  • C#
  • Web++
  • by_封爱
加入社区
  • 近7日
  • 近30日
  • 至今
社区公告

让您成为最强悍的C#开发者

试试用AI创作助手写篇文章吧