在winform中的button,点击后先设置enable为false,中间处理其他,最后设置enable为true
但是执行过程中再点击button,依然可以执行click
private void button1_Click(object sender, EventArgs e)
{
button1.Enabled = false;
textBox1.Text += "在执行中········";
//process something
textBox1.Text += "执行完毕!";
button1.Enabled= true;
}
这问题怎么解决
我很关心你的 // process something 到底是什么?
执行一个函数,调用webservice,是个耗时的操作
@xiaoyaozhe: 也就是说 // process something 是阻塞操作了。你可以见一个简单的WinForm程序,然后添加一个Button,然后在Click中这样写:
button1.Enabled = false;
Thread.Sleep(10000);
button1.Enabled = true;
然后你告诉我,你是不是可以在 10 秒内依然可以点击 button.
@程序猿.码农: 单独Sleep我试过,是可以,但是没有解决我这个情况,我也感到很奇怪,我没有用异步,因为耗时操作有好多是改变界面的,当然我可以将ui改变的部分独立出来,不过还没尝试
@xiaoyaozhe: 既然可以,那你就应该找你的代码逻辑的问题。比如 // process something 执行的时间要小于你两次鼠标点击的时间,或者 // process something 执行中更改了button1.Enabled 属性。
@程序猿.码农: 你好,首先谢谢你的回答。// process something没有更改enable属性,执行时间绝对大于两次点击间隔,因为第二次点击时候button是灰色的,并且界面是假死的
我想用 backgroundworker 控件实现,dowork处理远程查询,complete更新ui,但是complete事件一直不触发怎么回事?
//测试代码
private void btnSearch_Click(object sender, EventArgs e)
{
btnSearch.Enabled = false;
bgwSearch.RunWorkerAsync();
}
void bgwSearch_RunWorkerCompleted(object sender, RunWorkerCompletedEventArgs e)
{
Console.WriteLine("complete");
btnSearch.Enabled = true;
}
void bgwSearch_DoWork(object sender, DoWorkEventArgs e)
{
Console.WriteLine("dowork");
}
@xiaoyaozhe: 如果 // process something 没有更改,那就是别的地方更改了。如果都没有,那只能说明一个问题,你并没有把场景描述清楚,而是根据你自己的臆断认为问题是button在禁用的条件仍能点击。
@程序猿.码农: 也就是说,你是怎么判断出button在禁用条件下仍能点击并激发click事件的?
@程序猿.码农: 第一次点击,先disable,再执行耗时操作,所以界面是卡的状态,并且button是灰色的,然后再点击button,等一会儿(估计是第一次执行完全以后),第二次的点击就会响应,因为在断点处中断了
@xiaoyaozhe: 我测试过了,的确会有两次click事件,我给你那段代码你告诉我不会,实际也会。
@程序猿.码农: 问题出在设置button.Enabled = false; 后,button 并没有被禁用,所以它仍然能响应鼠标点击,只有当该相应事件的函数返回时,它才真正的处于禁用状态。
@程序猿.码农: sleep那段代码我测试时候加了句messagebox.show,只中断了一次,去掉以后就中断两次
@程序猿.码农: 这是因为消息机制引起的问题,如果处理click事件的函数执行时间过长,那么下一次点击的消息会存入消息队列,等到当前click处理函数退出以后,再从消息队列获取此消息执行。你可以使用我提供的代码,多次点击button,你会看到多次的重复执行。
解决此问题的办法是尽可能的让click事件处理函数的执行时间缩短,更严谨的做法是自己设置同步事件,忽略无效的点击。
@程序猿.码农: backgroundworker的问题我找到了,在winform构造函数里面我执行了如下尝试:
1.button.performclick(),无反应,即button_click未执行
2.将button_click中代码拷贝,即backgroundworker.runasyc(),则complete事件不触发
3.button_click(btnSearch,null),则complete事件不触发
4.什么都不做,则点击button后完全正常,即第一次点击button变灰,再点击不会触发click,直到真正执行完返回
希望帮忙看看怎么回事,谢谢
@xiaoyaozhe:
1, 构造函数里肯定不行,不用尝试了,不仅是click事件,其它例如ComboBox SelectChanged事件也一样。
后面三个问题,我觉得你仍然在错误的描述你的问题,我没法回答你,除非我有你的代码,否则我只能去猜你那里概念理解错了才得出这样的结论。所以,我需要现场,需要用我的知识来还原你的代码逻辑错误。
@程序猿.码农: 非常感谢你的回答,这个问题总算告一段落,只要在构造函数里面不操作backgroundworker和button_click,而是直接将dowork的工作执行就没问题,button也可以正常的操纵backgroundworker了。谢谢,诲人不倦啊你,我也该结贴了
没啥好说的:
把 调用 webservice 改成异步调用
完成后回调 执行
button1.Enabled= true;
webservice已经是异步的,但对结果的处理和对ui的改变是同步的
情况是这样的,点击以后button变灰,再点击,会等到上次的返回后再执行,就好像有个捕获点击的列表似的
button1.Enabled = false;
Thread.Sleep(10050);
button1.Enabled = true;
我这样写是不能click的。不过2L貌似说的对
谢谢回答,博客园就是好,呵呵
用多线程吧.子线程完成后让按钮好用.
backgroundworker其实就是用的多线程,已经解决了
楼主看你的代码似乎是要防止重复点击的事情,虽然我不知道你的代码具体要干嘛,但是我给你个建议:用一个全局变量,进入click事件时置一个状态,完了后把状态改回去,这样即可。
上面的虽然把问题绕过去了,但是没有全部源码的情况下我只有这个建议-
虽然已经解决了,还是谢谢回答啊
button.Refresh()
与楼主遇到同样的关题,主要是很多操作界面上控件的,就算用backgroundwork也会出现问题。
winform控件的enabled属性更改,只有在点击事件执行完后才会生效,所以我还是用线程处理了
在click中设置enabled,然后new thread,在thread内需要操作UI的地方,执行下面的RunMethod即可
private void RunMethod(Action action, Control contol)
{
try
{
if (InvokeRequired)
{
contol.Invoke(action);
}
else
{
action();
}
}
catch (InvalidOperationException)
{
// handleCreated exception
}
}
@xiaoyaozhe: 是的最后是以Invoke方式处理,确实很麻烦,因为要把操作界面的全部分开。