长时间操作前强制重新绘制

7
当你有一个按钮,执行如下操作:

当你有一个按钮,执行如下操作:

Private Function Button_OnClick

    Button.Enabled = False

    [LONG OPERATION] 

End Function

那么按钮将不会变灰,因为长时间的操作阻止了UI线程重新绘制控件。我知道正确的设计是启动一个后台线程/调度程序,但有时对于简单的操作来说这太麻烦了。

那么如何强制禁用状态下的按钮重新绘制呢?我尝试在按钮上使用.UpdateLayout(),但没有任何效果。我还尝试了System.Windows.Forms.DoEvents(),这通常在使用WinForms时有效,但它也没有效果。

3个回答

8
以下代码将完成您所需的操作。但我不建议使用它。长时间操作请使用BackgroundWorker类。它易于使用且非常稳定。
这里是代码:
   public static void ProcessUITasks() {            
        DispatcherFrame frame = new DispatcherFrame();
        Dispatcher.CurrentDispatcher.BeginInvoke(DispatcherPriority.Background, new DispatcherOperationCallback(delegate(object parameter) {
            frame.Continue = false;
            return null;
        }), null);
        Dispatcher.PushFrame(frame);
    }

这里有一个如何使用BackgroundWorker的示例。


他非常明确地表示知道但不使用Dispatcher/Backgroundworker :) - edvaldig
2
@edvaldig:我已经强调不要使用它,但是我给了他他正在寻找的代码。我认为这不值得你给我一个-1。如果我的代码不起作用,请给我一个-1,但不是因为提供一些额外的建议。我认为这不公平。 - HCL
1
你说得对,我太匆忙了,评论点赞作为补偿 :) - edvaldig
如果想通过COM打开另一个应用程序(我认为应该在UI线程/ STA Apartment上完成),怎样使用BackgroundWorker线程? - Eric Ouellet

0

InvalidateVisual(); @HCL是正确的...不要这样做

就像你所说的,最好启动一个后台线程/调度程序,并保持UI线程未阻塞。考虑查看微软的响应式扩展库,用于高级异步UI编程。


这样做是不行的。无效化仅会使要重新绘制的区域失效,但它不会进行重新绘制。 - HCL
@HCL,对我来说运行良好,请查看函数文档:使元素的渲染无效,并强制进行完整的新布局传递。 OnRender在布局周期完成后调用。 - edvaldig
你确定你的UI线程被阻塞了吗?我上次在.net3.5SP1下测试过,当时它没有工作。如果现在它能工作,那么他们一定改变了4.0的行为。然而,这对我来说将是一个很大的惊喜。 - HCL
响应式编程是否解决了在 UI 线程(STA apartment)上执行的 COM 长操作问题? - Eric Ouellet

0
在Windows.Forms中,您可以使用Button.Refresh()
在Windows.Forms或WPF中,您可以让消息泵重新绘制。Async/Await旨在使您能够在不使用HCL答案的情况下完成此操作。
Private Async Function Button_OnClick

    Button.Enabled = False

    Await Task.Yield

    [LONG OPERATION] 

End Function

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接