winforms 按钮禁用和启用

mm9b1k5b  于 2023-02-13  发布在  其他
关注(0)|答案(8)|浏览(225)

我有一个基于vb.net的Windows应用程序,当点击“GO”按钮时,一堆数据被加载到DB中。因此,在我的应用程序中,只要点击“GO”按钮,我就想禁用它,并希望在上传完成后重新启用它。现在,在btnGo_Click()的特定方法中,我有:

btnGo.Enabled = False

作为第一行和

btnGo.Enabled = True

作为同一方法中的最后一行。
但是我不明白为什么“GO”虽然看起来被禁用了,但在处理过程中仍然允许点击。而且如果我删除了最后一行,它会被永久禁用,不允许点击事件。
请告诉我我做错了什么?
编辑(日期:2012年1月25日):我按照同事的建议做了修改,但我现在面临一个新问题。我面临的问题是文本框得到更新,但并不总是这样。我已经在后台工作线程的“_ProgressChanged”事件中更新了我的文本框。在我的情况下,如果有10条记录被上载。那么在文本框中有10行更新。但只有几行显示在文本框中。又是重新粉刷的问题吗?请建议......因为所有其他的事情都是按照你的建议做的

q8l4jmvw

q8l4jmvw1#

你没有做错任何事。问题是UI直到你的事件处理方法内部的代码完成执行后才会更新。然后,按钮被禁用,然后迅速地被启用。
这就解释了为什么如果您忘记在事件处理程序方法结束时 reenable button控件,它仍然是禁用的-因为您在方法的第一行告诉它禁用按钮。
这是一个典型的例子,说明了为什么永远不要在事件处理程序方法内部执行长时间运行的计算任务,因为它会阻止UI更新。计算实际上需要在单独的线程上进行。但是不要尝试手动创建线程,也绝对不要尝试从单独的线程更新UI。相反,可以使用BackgroundWorker component来自动处理所有这些问题。链接的MSDN文档中有关于如何使用它的很好的示例。
在启动BackgroundWorker之前禁用该按钮,然后在其Completed事件中重新启用它,表示数据库加载完成。

eqoofvh9

eqoofvh92#

因为你正在尝试执行一个可能需要一些时间的函数,我建议你使用线程。在.NET中有一个BackgroundWorker组件,它非常适合异步执行任务。
单击按钮后,调用BackgroundWorker,如下所示:

if not bgwWorker.IsBusy then
   btnGo.enabled = false
   bgwWorker.RunWorkerAsync()
end if

并使用完成的事件再次启用按钮:

Private Sub bgwWorker_DoWork(ByVal sender As System.Object, _
                 ByVal e As System.ComponentModel.DoWorkEventArgs) _
                 Handles bgwWorker.DoWork
' Do your things    
End Sub

Private Sub bgwWorker_RunWorkerCompleted(ByVal sender As System.Object, _
                         ByVal e As System.ComponentModel.RunWorkerCompletedEventArgs) _
                         Handles bgwWorker.RunWorkerCompleted
' Called when the BackgroundWorker is completed.
btnGo.enabled = true
End Sub

在上面的示例中,我使用bgwWorker作为BackgroundWorker的示例。

83qze16e

83qze16e3#

UI线程一有空闲时间就处理按钮单击事件。禁用按钮后,代码就会使UI线程保持忙碌状态。在方法结束时,重新启用按钮,然后退出方法并允许空闲时间。因此,在处理单击事件的时间点,按钮已经启用,因此您的单击是“可识别的”。
正如其他人已经建议的那样,解决方案是使用Backgroundworker。
不要尝试使用doEvents()作为解决方案(永远不要这样做),因为这很容易引入其他微妙的问题。也就是说,您可以在代码中使用一些实验性的doEvent来证明上述解释。您将看到,如果在按钮重新启用之前执行doEvent,则会放弃单击。另一方面,在button.disable之后直接执行doEvents(以“更新GUI”),如果在单击之前执行,则不会有帮助。

kq0g1dla

kq0g1dla4#

如果您的btnGo_Click()在主线程内运行,则UI无法在耗时的任务内正确更新。
执行所需操作的最佳方法是在BackgroundWorker中运行方法。

xoshrz7s

xoshrz7s5#

我刚刚试着禁用一个按钮,Update ing表单,Sleep ing,然后再次启用它。它仍然在启用后执行单击(在禁用按钮的情况下“睡眠”时完成的单击)。
我猜是“记住”的声音。
(EDIT(我是用C#完成的。)

woobm2wo

woobm2wo6#

管理提交按钮的状态通常不是一个好主意,而是在提交时执行验证。

ogq8wdun

ogq8wdun7#

我想对这里描述的答案增加2个增强,那就是“在另一个线程中完成工作”。
1.确保始终调用按钮.enable=true
1.a.您应该在button_click中使用try块。如果在启动线程时出现错误,CATCH应该重新启用按钮。
1.b.任务完成回调还应确保使用try/catch/finally启用按钮1.c.任务超时还应重新启用按钮
1.一个常见的错误是快速点击者连续快速点击按钮两次。这是可能的,因为即使不太可能,两次点击的消息也可能在按钮被禁用之前排队和处理。你不能假设事件同步发生。
恕我直言,最好的做法是使用静态变量。将其初始化为0。在第一条语句中将其设置为1,然后按照POINT 1中的指导将其设置为0。
如果值〉0,单击按钮时的第二条语句应简单返回/退出
如果你正在使用一个工作线程,静态变量可能必须位于代码中。我不建议把它作为一个窗体级变量。

xfb7svmp

xfb7svmp8#

我有一个稍微不同的问题,不能调用点击。我有一个例程,打开/关闭用户界面的基础上验证例程。

  • 我会说我不同意在提交时进行验证的建议。2如果我们能够判断表单是无效的,则不应该启用该按钮。

我的问题是我从几个地方调用验证。其中一个调用是网格的CustomCellDraw事件,该事件非常频繁地触发。
因此,虽然看起来我只是简单地禁用/启用了几次按钮,但我真的几乎一直在这样做。
我可以通过在表单上放置一个标签和做一个console.log之类的事情来解决问题。我立即意识到按钮。启用是 Flink 的,这引导我走上了正确的解决问题的道路。
我意识到这解决了与op描述的不同的根本原因。但它确实解决了op描述的问题。

相关问题