4

我的XAML 中有一个其属性绑定到我的 ViewModel 上的一个属性(它实现了)。一个单独的按钮会启动一个长时间运行(2-3 秒)的进程,如下所示:please wait TextBlockVisibilityIsBusyINotifyPropertyChanged

IsBusy = true;

try
{
    // Do some long-running process
}

finally
{
    IsBusy = false;
}

但该please wait消息从未出现。我假设操作在 UI 线程上运行,因此没有机会刷新?如果我在单独的线程上运行上述代码,它确实有效,但我不希望用户在操作运行时做任何事情 - 我很高兴 UI 能够freeze.

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

4

3 回答 3

5

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

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

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

于 2013-01-30T16:35:06.097 回答
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

于 2013-01-30T15:37:31.043 回答
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
}
于 2013-01-30T15:40:27.040 回答