【问题标题】:Busy indicator does not show until data shows直到数据显示忙碌指示符才会显示
【发布时间】:2015-05-18 21:06:18
【问题描述】:

我的项目中有一个控件,它提供了一个繁忙的指示器(旋转圆圈)。我希望它在用户选择文件以将数据加载到数据网格时运行。但是,在填充我的数据网格之前,繁忙的指示器不会显示。如何在检索数据时显示繁忙指示器?我相信我应该使用线程,但对它们还不太了解,并且正在努力学习。我尝试了很多不同的方法,下面是我最近的尝试,我不知道我是否接近。

public void DoWork()
{
this.StartProgressBar();

Task.Factory.StartNew(() =>
    {
        UIDispatcher.Current.BeginInvoke(() =>
            {
                if (fileCompleted != null && !string.IsNullOrEmpty(fileCompleted.SelectedFile))
                {
                    this.TestResults.Clear();

                    LoadedFileInfo info = this.Model.OpenTestCompleted(fileCompleted.SelectedFile);

                    foreach (var model in info.Sequence.Models)
                    {
                        foreach (var details in model.Tests)
                        {
                            this.TestResults.Add(new TestResultsModel(details, model.Name.Substring(0, model.Name.IndexOf('.'))));
                        }
                    }
                }
            });
    });
}

private void StartProgressBar()
{
    TaskScheduler scheduler = TaskScheduler.FromCurrentSynchronizationContext();

    CancellationToken cancelationToken = new CancellationToken();
    Task.Factory.StartNew(() => this.StopProgressBar()).ContinueWith(
        m => 
        {
            this.ToggleProgressBar = true;
        },
        cancelationToken,
        TaskContinuationOptions.None, 
        scheduler);
}

private void StopProgressBar()
{
    this.ToggleProgressBar = false;
}

【问题讨论】:

  • 你可能想看看 backgroundworker:msdn.microsoft.com/de-de/library/…
  • 感谢您的回复,我查看了它,但我不太了解它是否知道我在我的情况下是否正确使用了该示例。我不确定如何将我的代码放在上面并将其分解为后台任务。你能在这里提供任何帮助吗?

标签: wpf mvvm


【解决方案1】:

我真的同意@Ben,你应该研究如何使用任务。您正在创建后台线程,并且无论如何都在其中的 UI 线程上工作,这不可避免地会占用 UI 线程。尝试一些更简单的方法,看看它是否有效。就您的取消令牌而言,我不知道您如何以及是否能够重置它,因为它不是您班级中的属性,所以这里有一个没有它的示例..

这样的事情怎么样:

public void DoWork()
{
   //done on the UI thread
   this.ToggleProgressBar = true;

  //done on the background thread, releasing UI, hence should show the progress bar
  Task.Factory.StartNew(() =>
  {
      if (fileCompleted != null && !string.IsNullOrEmpty(fileCompleted.SelectedFile))
      {
          this.TestResults.Clear();
          LoadedFileInfo info = this.Model.OpenTestCompleted(fileCompleted.SelectedFile);

          foreach (var model in info.Sequence.Models)              
              foreach (var details in model.Tests)                  
                   this.TestResults.Add(new TestResultsModel(details, model.Name.Substring(0, model.Name.IndexOf('.'))));
       }
      //after all that (assumingly heavy work is done on the background thread,
      //use UI thread to notify UI
      UIDispatcher.Current.BeginInvoke(() =>
          {
             this.ToggleProgresBar = false;
          }
});

}

【讨论】:

  • 我猜 TestResults 是一个 ObservableCollection(基于问题的标签),这意味着它需要在 UI 线程上进行修改。 OP 可以对每个项目使用 BeginInvoke 来执行此操作,但如果涉及大量项目,这实际上可能会出现问题。 WPF 绑定方案的最佳性能(假设 OP 不想显示部分结果)是用新集合替换整个 TestResults 属性,然后为 TestResults 属性引发适当的 PropertyChanged 通知。
  • 感谢您的建议。我将更深入地研究任务,并尝试 BeginInvoke 并用我的结果发表评论。
  • 我同意@Dan Bryant 的观点。一个快速的测试是将 ObservableCollection 更改为一个列表,仍然在后台线程中填充它,完成后,就在 ToggleProgressBar = false, RaisePropertyChanged("TestResults");这应该更新绑定,而不会产生由可观察集合创建的喋喋不休。
  • 您还可以扩展 ObservableCollection 以删除它在添加每个项目时创建的喋喋不休。这将使性能提高十倍。查看帖子:stackoverflow.com/questions/16858479/…
猜你喜欢
  • 1970-01-01
  • 2014-10-04
  • 2015-08-04
  • 1970-01-01
  • 2018-06-18
  • 2019-01-20
  • 2011-05-20
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多