尝试在长时间运行的操作期间在WPF中显示“请稍候”消息

时间:2013-01-30 15:29:22

标签: c# wpf visibility inotifypropertychanged textblock

我的XAML中有一个 please wait TextBlock,其Visibility属性绑定到我的ViewModel上的IsBusy属性(实现{ {1}})。一个单独的按钮启动一个长时间运行(2-3秒)的过程,如下所示:

INotifyPropertyChanged

IsBusy = true; try { // Do some long-running process } finally { IsBusy = false; } 消息永远不会出现。我假设操作在UI线程上运行,因此没有给它机会刷新?如果我在一个单独的线程上运行上面的代码, 可以工作,但我不希望用户在操作运行时做任何事情 - 我很高兴用户界面{{1} }。

如何显示 please wait 讯息?或者我会更好地在后台线程上运行它并(以某种方式)锁定UI持续时间?我正在使用.Net 4顺便说一句。

3 个答案:

答案 0 :(得分:5)

你是对的,它没有更新,因为你在同一个线程上运行代码,所以在你的进程完成之后,渲染才会继续。

您说您没有使用后台线程,因为您不希望用户在操作运行时执行任何操作,但完全锁定您的应用程序绝不是一个好主意。

更好的解决方案是将Form / Window / UserControl / etc的IsEnabled绑定到IsBusy属性。然后当它变忙时,整个表单被禁用以防止用户修改它,同时不锁定你的应用程序。

答案 1 :(得分:1)

首先Visibility属性不是bool,所以如果要将bool变量绑定到它,则需要使用IValueConverter,其次,是的,你是对的虽然UI线程忙于长时间运行,但它不会执行任何其他操作,包括可见性更改。

我建议使用WPF Toolkit BusyIndicator期望放置自己的面板,它具有IsBusy bool属性。

另外froozen UI不是用户友好的,通常我使用这个片段

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

另请注意检查ContinueWith方法中的错误,否则您将在Task dispose上获得例外

答案 2 :(得分:0)

如果您在单独的线程上运行代码,您仍然可以通过Dispatcher.BeginInvoke Method访问用户界面。

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
}