如何在后台线程运行时阻止 Winforms UI
我继承了一个 Winforms 应用程序,该应用程序从 UI 线程对应用程序服务器进行大量长时间运行的调用,因此 UI 在相当长的一段时间内保持无响应、无法使用、无法关闭。 (这让我真的AAAAAAAAARGH!)
我计划将服务器调用移至后台线程并禁用 UI - 但可移动且可移动。 可关闭 - 当后台线程执行其工作时。
那么禁止用户输入我的应用程序的最佳方法是什么? 我正在考虑“模态进度对话框”,但我更喜欢一种不会强迫我将视觉效果投射到用户面前的解决方案(某些服务器操作在不到 500 毫秒内运行,因此对话框不是最佳...)
Winforms中有没有什么方法可以阻止用户启动操作或更改应用程序中的数据,同时允许执行一些选择的操作(调整大小、显示、隐藏和家庭以及用户关闭应用程序)窗户)? 我更喜欢一种不会让我访问表单中的每个 UI 元素并将其设置为禁用的方法...它们有很多,并且该应用程序确实在 UI 设计器中“被黑了,直到它显示出华丽的东西” ” 源代码的风格。 在发布日期之前无法重构所有臭味......
哦,顺便说一下,这个应用程序位于 .net Framework 2 中
I've inherited a Winforms application that does a lot of long running calls into the application server from the UI thread, so the UI stays unresponsive, unusable, unclosable for quite some time. (Which makes me really go AAAAAAAAARGH!)
I plan to move the server calls to a background thread and have the UI disabled - but movable & closable - while the background thread does its work.
So what would be the best way to inhibit user input to my application? I'm thinking along the lines of "modal progress dialog", but I'd prefer a solution that does not force me to throw visuals into the face of the user (some server operations run within less than 500ms so a dialog is not optimal ...)
Is there any way in Winforms to prevent the user from launching actions or changing data in the application while letting through a few select things (resize, show, hide and family and the user closing the window)? I'd prefer a way that does not make me access every UI element in my forms and set it to disabled ... there are quite a lot of them and that application really has a "hacked in the UI designer until it shows flashy things" style of source code. No way of refactoring EVERY smelly thing until release date ...
Oh, by the way, this App lives in .net framework 2
如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。
绑定邮箱获取回复消息
由于您还没有绑定你的真实邮箱,如果其他用户或者作者回复了您的评论,将不能在第一时间通知您!
发布评论
评论(6)
我知道的唯一方法是禁用部分/所有控件。 但是,根据控件的布局方式,没有必要将每个控件设置为禁用 - 当容器控件被禁用时,它的所有子控件也会被禁用。 例如,如果您有一个带有某些控件的
GroupBox
,如果您将GroupBox
设置为禁用,则GroupBox
中的所有控件都将也被禁用。The only way I know of is to get some/all controls as disabled. However, depending on how the controls are laid out, it isn't necessary to set every control as disabled - when a container control is disabled, then all of its children are disabled, too. For example, if you have a
GroupBox
with some controls, if you set theGroupBox
to disabled, then all of the controls within theGroupBox
will be disabled, too.选择一些上层容器控件(可能是表单本身),并将其 Enabled 属性设置为 false。 放置在该控件上的所有控件都将被禁用,这将阻止它们接收输入。
Choose some upper level container control (might be the form itself), and set it's Enabled property to false. All controls placed on that control will be disabled, which will prevent them from receiving input.
简单地启用/禁用按钮的问题是,当任务运行时,UI 事件仍然会添加到消息队列中......
假设您有一个“搜索”按钮和一个“重置”按钮。 单击“搜索”时,您将禁用这两个按钮。 搜索会持续一段时间。 如果用户单击重置,即使已禁用,搜索也会在完成后立即重置。
添加一个
解决这个问题的快速而肮脏的方法是在重新启用按钮之前立即 调用。 DoEvents() 将处理控件上的所有单击事件,对于仍处于禁用状态的控件,该事件将被忽略。
The problem with simply enabling/disabling buttons is that UI events will still get added to the messagequeue while the task is running....
Say you have a Search button and a Reset button. When you click Search, you disable both buttons. The search runs for a while. If the user clicks Reset, even while it's disabled, the search will reset immediately upon completing.
The quick and dirty way around this is to add an
call immediately before re-enabling the buttons. DoEvents() will process all the click events on the controls, which will be ignored for controls that are still disabled.
在 Win32 API 级别,有一个 EnableWindow您可以使用该函数禁用任何窗口手(当然,您需要获取主窗口以及任何其他顶级窗口的底层句柄)。 不过我还没有在 WinForms 中测试过它。 (我很确定 User32 级别上还有其他答案,但我现在不记得 API 调用。)
注意:这不会使控件变灰,从可用性的角度来看,这会降低其实用性(用户只会看到“冻结的应用程序”)。 如果您至少设置一个沙漏光标,情况会稍微好一些。
然而,这是处理异步处理的一种快速而肮脏的方法。 您真的需要将用户锁定在整个应用程序之外吗? 也许只是在请求正在进行时应该禁止一些功能?
On the Win32 API level, there's a EnableWindow function you can disable any window hand with (you need to get the underlying handle of your main window, of course, and of any other top level windows). I haven't tested it in WinForms, though. (I'm pretty sure there are other answers on the User32 level, but I can't remember the API calls right now.)
Note: this doesn't grey out controls, which decreases its utility from a usability point of view (the user just sees a 'frozen application'). It gets marginally better if you at least set an hourglass cursor.
However, this is a quick-and-dirty way of dealing with asynchronous processing. Do you really need to lock the user out of your entire application? Perhaps it's just a few functions that should be banned while a request is underway?
不幸的是,对于 WinForms,您可能需要在单个共享方法中禁用/启用按钮。 这是 WPF 相对于 Windows 窗体的优势之一 - 处理这些情况要容易得多。
至于不阻止您的 UI - 您需要将调用转移到异步编程模型。 对于您的情况,我建议您查看一下 ThreadPool。
您需要执行一些操作,例如让按钮禁用控件,调用线程池上的操作,然后在完成后重新启用它们。
Unfortunately, with WinForms, you'll probably need to disable/enable the buttons in a single shared method. This is one of the advantages WPF brings over windows forms - it's much easier to handle these situations.
As for not blocking your UI - you'll need to move your calls to an asynchronous programming model. In your case, I'd recommend taking a look at the ThreadPool.
You'll want to do something like have the button disable your controls, call out your operation on the thread pool, then reenable them on completion.
我在这里回答一个旧线程,但我看到这个问题并记得我的一个旧 WinForm 应用程序,我在禁用表单的同时仍然允许调整其大小和移动等方面遇到了同样的问题。我加载了我的代码并发现解决方案是:
严格来说,您不必使用面板控件,任何容器控件都应该表现出相同的行为。 即使是 PictureBox 控件也能做到这一点!
I'm answering an old thread here, but I saw this question and remembered an old WinForm app of mine where I had the same problem of disabling a form while still allowing it to be resized and moved etc. I loaded up my code and found the solution was to:
Strictly speaking, you don't have to use a Panel control, any Container Control should exhibit the same behaviour. Even a PictureBox control will do the trick!