如何在后台线程运行时阻止Winforms UI

时间:2009-03-15 18:11:35

标签: .net winforms multithreading .net-2.0

我继承了一个Winforms应用程序,该应用程序从UI线程对应用程序服务器执行大量长时间运行的调用,因此UI在相当长的一段时间内保持无响应,无法使用,无法关闭。 (这让我真的去了 AAAAAAAAAARGH!

我计划将服务器调用移到后台线程并禁用UI - 但可移动&可关闭 - 当后台线程完成它的工作。

那么阻止用户输入我的应用程序的最佳方法是什么?我正在思考“模态进度对话框”,但我更喜欢一种不会强迫我将视觉效果抛到用户面前的解决方案(某些服务器操作在不到500毫秒内运行,因此对话框是最佳...)

Winforms中是否有任何方法可以阻止用户启动操作或更改应用程序中的数据,同时通过一些选择(调整大小,显示,隐藏和家人以及关闭窗口的用户)?我更喜欢一种不会让我访问表单中的每个UI元素并将其设置为禁用的方式...它们中有很多并且该应用程序确实“在UI设计器中被黑客攻击,直到它显示出华而不实的东西“源代码的风格。在发布日期之前,没有办法重构每个有臭味的东西......

哦,顺便说一下,这个应用程序存在于.net framework 2

6 个答案:

答案 0 :(得分:6)

我知道的唯一方法是将部分/全部控件设置为禁用。但是,根据控件的布局方式,不必将每个控件设置为禁用 - 当禁用容器控件时,也会禁用其所有子控件。例如,如果您有GroupBox包含某些控件,如果您将GroupBox设置为禁用,那么GroupBox中的所有控件也将被禁用。

答案 1 :(得分:5)

选择一些上层容器控件(可能是表单本身),并将其Enabled属性设置为false。放置在该控件上的所有控件都将被禁用,这将阻止它们接收输入。

答案 2 :(得分:3)

简单地启用/禁用按钮的问题是,在任务运行时,UI事件仍会被添加到消息队列中....

假设您有“搜索”按钮和“重置”按钮。单击“搜索”时,将禁用这两个按钮。搜索运行了一段时间。如果用户单击“重置”,即使它已被禁用,搜索也会在完成后立即重置。

快速而肮脏的方法是添加

Application.DoEvents();

在重新启用按钮之前立即调用。 DoEvents()将处理控件上的所有单击事件,对于仍然禁用的控件,将忽略这些事件。

答案 3 :(得分:1)

在Win32 API级别上,有一个EnableWindow函数,您可以禁用任何窗口处理(当然,您需要获取主窗口的底层句柄,以及任何其他顶级窗口)。不过,我还没有在WinForms中测试它。 (我很确定User32级别还有其他答案,但我现在还记不起API调用了。)

注意:这不会使控件变灰,从可用性的角度来看会降低其效用(用户只看到“冻结的应用程序”)。如果你至少设置一个沙漏光标,它会稍微好一点。

但是,这是一种处理异步处理的快捷方式。您真的需要将用户锁定在整个应用程序之外吗?也许只是在请求正在进行时应该禁止的一些功能?

答案 4 :(得分:0)

不幸的是,使用WinForms,您可能需要在单个共享方法中禁用/启用按钮。这是WPF为Windows窗体带来的优势之一 - 处理这些情况要容易得多。

至于不阻止你的UI - 你需要将你的调用转移到异步编程模型。在您的情况下,我建议您查看ThreadPool。

你想要做的事情就是让按钮禁用你的控件,在线程池上调用你的操作,然后在完成时重新启用它们。

答案 5 :(得分:0)

我在这里回答了一个旧帖子,但是我看到了这个问题并想起了我的一个旧的WinForm应用程序,我遇到了同样的问题,即禁用表单同时仍然允许它重新调整大小并移动等等。我加载了我的代码,发现解决方案是:

  1. 在窗体上放置一个Panel控件,并为Dock属性赋予DockStyle.Fill值。
  2. 不是将所有表单的组成顶层控件直接放入表单中,而是将它们放入Panel控件中。
  3. 现在有了神奇的一点 - 当您想要禁用表单的控件时,只需将Panel的Enabled属性设置为false即可。执行此操作时,Panel控件包含的所有控件也将被禁用,但表单本身仍然启用,因此可以调整大小等。要恢复所有控件的状态,只需将Enabled属性设置回true即可。
  4. 严格来说,您不必使用Panel控件,任何Container Control应该表现出相同的行为。即使是PictureBox控件也可以做到这一点!