WPF绑定渲染Gui进度

时间:2010-12-29 07:18:58

标签: wpf c#-4.0 wpf-controls binding prism

我知道这里和那里有几个实现,但我仍然无法“锁定”真正有用的东西......

每当我将一些组件DataContext或ItemsSource设置为某个大对象时,就会出现“渲染时冻结的GUI”,这会让应用程序变得烦人(即使使用虚拟化)。

我知道我可以迭代对象并逐个设置项目并显示进度,但我正在寻找一些其他方法,可以让我在GUI渲染时显示一些移动指示。我也喜欢有一些进度条,不仅让鼠标光标改变。

有没有一种可行的方法来实现以下目标?

非常感谢

3 个答案:

答案 0 :(得分:3)

Zamboni示例非常好,但仍然无法解决冻结的GUI问题

如上所述,当GUI忙于渲染时,目前还没有简单的方法可以更新gui控件。

我目前发现了一些'活着并且踢' gui正在呈现的事件,但是在不需要的时候它应该被关闭,因为它可以每秒发射60次。

CompositionTarget.Rendering += ReportRenderProgress;

然后,您可以实施ReportRenderProgress(),以表示您要更新进度条。目前,我没有在WPF中看到任何更好的解决方案,以便在渲染时更新进度指示,因此我将此标记为答案。

答案 1 :(得分:2)

这实际上是一个问题。您正在使用GUI线程来填充数据(从对象结构到GUI)。 GUI线程既需要读取Windows消息队列(防止应用程序冻结,允许移动/响应应用程序),也需要对GUI进行任何更新。

一种解决方案可能是在绑定后缓慢填充对象结构。这必须从GUI线程完成,因此您可以添加DoEvents()和/或一些百分比指示符+强制刷新,以使应用程序看起来活着。

我很想知道是否有人有更好的解决方案。

答案 2 :(得分:2)

BackgroundWorker拥有您需要的一切。

修改

在WPF中,Dispatcher被自动用于调用跨线程方法调用。 查看MSDN杂志中的Build More Responsive Apps With The Dispatcher

我还将来自ViewModel的一些代码片段放在一起,显示了BackgroundWorker更新进度条。

<ProgressBar 
    VerticalContentAlignment="Stretch" VerticalAlignment="Stretch"
    HorizontalAlignment="Stretch"
    Minimum="0" Maximum="100"
    Value="{Binding Path=BarPosition, Mode=TwoWay}"/>


// configure the background worker...
_backgroundWorker = new BackgroundWorker();
_backgroundWorker.WorkerReportsProgress = true;
_backgroundWorker.WorkerSupportsCancellation = true;
_backgroundWorker.DoWork += new DoWorkEventHandler(_backgroundWorker_DoWork);
_backgroundWorker.RunWorkerCompleted += new RunWorkerCompletedEventHandler(_backgroundWorker_RunWorkerCompleted);
_backgroundWorker.ProgressChanged += new ProgressChangedEventHandler(_backgroundWorker_ProgressChanged);

// control progress bar position
private int _barPosition = 0;
public int BarPosition
{
   get { return _barPosition; }
   set
   {
      _barPosition = value;
      OnPropertyChanged("BarPosition");
   }
}

// long operation
void _backgroundWorker_DoWork(object sender, DoWorkEventArgs e)
{
  BackgroundWorker bw = sender as BackgroundWorker;
  if (bw != null)
  {
     int pos;

     for (int i = 0; i < 100; ++i
     {
        // report progress here for our long running operation..
        pos = i/100;
        bw.ReportProgress(pos);
        Thread.Sleep(1000);            // fake long operation
     }
  }
}

// report progress,,,
void _backgroundWorker_ProgressChanged(object sender, ProgressChangedEventArgs e)
{
   BackgroundWorker bw = sender as BackgroundWorker;
   if (bw != null)
   {
      BarPosition = e.ProgressPercentage;
   }
}

// reset scroll bar position
void _backgroundWorker_RunWorkerCompleted(object sender, RunWorkerCompletedEventArgs e)
{
   BackgroundWorker bw = sender as BackgroundWorker;
   if (bw != null)
   {
     BarPosition = 0;

     // Forcing the CommandManager to raise the RequerySuggested event to refresh UI...
     CommandManager.InvalidateRequerySuggested();
   }
}