在WPF中,如何在长时间运行的操作期间显示“请稍候”消息?

4

我在XAML中有一个请稍等TextBlock,它的Visibility属性绑定到我的ViewModel上的一个IsBusy属性(该ViewModel实现了INotifyPropertyChanged)。单独的按钮启动一个长时间运行的过程(2-3秒),如下所示:

IsBusy = true;

try
{
    // Do some long-running process
}

finally
{
    IsBusy = false;
}

但是“请等待”消息从未出现。我假设操作正在运行在UI线程上,因此没有给它刷新的机会?如果我在单独的线程上运行上述代码,它确实可以工作,但是我不希望用户在操作运行时做任何事情 - 我很高兴让UI冻结。
如何显示“请等待”消息?或者我最好在后台线程上运行它,并在此期间锁定UI?顺便说一下,我正在使用.NET 4。

1
为什么不在后台线程中运行它,并将您的表单/窗口/用户控件等的“IsEnabled”绑定到“IsBusy”属性?然后,当它变得繁忙时,整个窗口都会被禁用,以防止用户在不锁定应用程序的情况下修改它? - Rachel
@Rachel 有时候最简单的解决方案是最好的 - 谢谢!不过现在又遇到了另一个问题,这个问题留待下一个SO问题来解决吧... - Andrew Stephens
好的,我已经为您将那个评论扩展成了一个答案 :) - Rachel
3个回答

5
您是正确的,它没有更新,因为您正在同一个线程上运行代码,因此渲染要等到进程完成后才会继续进行。
您说您不使用后台线程是因为您不希望用户在操作运行时做任何事情,但完全锁定您的应用程序永远都不是一个好主意。
更好的解决方案是将表单/窗口/用户控件等的"IsEnabled"绑定到"IsBusy"属性。然后当它变得繁忙时,整个表单将被禁用以防止用户修改它,同时不会锁定您的应用程序。

1

首先,Visibility属性不是bool类型的,因此如果您想将bool变量绑定到它,您需要使用IValueConverter。其次,是的,您是正确的,当UI线程忙于长时间运行操作时,它将不执行任何其他操作,包括可见性更改。

我建议使用WPF Toolkit BusyIndicator而不是放置自己的面板,它有IsBusy bool属性。

另外,冻结的UI并不用户友好,通常我使用这个片段。

IsBusy = true;
Task.Factory.StartNew(() => 
{ 
  // Do work. 
})
.ContinueWith(t=>IsBusy=false, 
                        TaskScheduler.FromCurrentSynchronizationContext());

此外,请注意检查 ContinueWith 方法中的错误,否则您将在 Task 销毁时出现异常。

0

如果您在单独的线程上运行代码,仍然可以通过Dispatcher.BeginInvoke 方法访问UI。

if (!YOURCONTROL.Dispatcher.CheckAccess())
{
    YOURCONTROL.Dispatcher.Invoke(System.Windows.Threading.DispatcherPriority.Normal,
        new Action(delegate()
        {
            //do something with the control/form/...
        }));
}
else
{
    //update your control
}

这就是我一开始所做的,但正如最初所述,我不想在后台线程中运行。回过头来看,最好以受控方式锁定UI,而不是让它冻结。 - Andrew Stephens

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