WPF进度条工作但在UI线程中阻止,即使使用异步

时间:2016-05-03 16:37:24

标签: c# wpf multithreading asynchronous progress-bar

我正在尝试在我的程序中实施不确定的进度条。我是线程新手,但据我所知,这里最好的选择之一就是添加一个异步方法,等待" heavy"功能来执行其结果。所以我写了这个:

public void Window_Loaded(object sender, RoutedEventArgs e)
{
    firstLoad();                         
}

private async void firstLoad()
{
    LW.Title = "Loading...";
    LW.Show();

    filterTextBox.Text = defaultSearch;
    await Task.Run(() => InitializeFilter());          
}

private void InitializeFilter()
{

//Asynchronous??? 
Dispatcher.BeginInvoke(new Action(() => {

//... some lines of code that takes some time to run. 

dataGrid.ItemContainerGenerator.StatusChanged += new EventHandler(closeLoadingWindow);

}));

private void closeLoadingWindow(object sender, EventArgs e)
{
    if (LW != null)
    {
        LW.closable = true;
        LW.Close();
    }
}

firstLoad在加载窗口时运行,显示一个不确定的LW loadingWindow,并运行InitializeFilter()方法(较重的一个)。最后,当填充并加载网格时,会触发一个事件,允许LW窗口关闭并关闭它(如果我没有使它无法关闭,有趣的用户可以关闭它点击或使用F4,这是不太好)。

系统工作正常,一切都按预期工作,但是加载栏被冻结,没有显示进度。在MainWindow中使用相同的LW栏进行类似的设置我缺少什么?提前致谢!

2 个答案:

答案 0 :(得分:1)

  

据我所知,这里最好的选择之一就是添加一个异步方法,等待" heavy"功能来执行其结果

最好的选择是使用Task.Run将繁重的处理移动到线程池,并使用await检索其结果。

当前的代码使用Task.Run移动到线程池,然后立即转身并使用Dispatcher在执行繁重处理之前移回UI线程。因此,它阻止了UI线程。

  

这个特定的DataGrid显示的是CollectionView,它不是线程安全的。

是的,您无法从线程池线程更新数据绑定对象。

最佳解决方案是将重处理与UI更新分开,如下所示:

public async void Window_Loaded(object sender, RoutedEventArgs e)
{
  await firstLoadAsync();
}

private List<FilterType> InitializeFilter()
{
  //... some lines of code that takes some time to run. 
}

private async Task firstLoadAsync()
{
  LW.Title = "Loading...";
  LW.Show();

  filterTextBox.Text = defaultSearch;
  var filterData = await Task.Run(() => InitializeFilter()); // Get the plain data on a background thread
  myCollectionView = new CollectionView(filterData); // Update the UI
  if (LW != null)
  {
    LW.closable = true;
    LW.Close();
  }
}

答案 1 :(得分:0)

不要使用您的调度员。微软有远见使用它的魔力(SynchronizationContext)能够更新在异步上下文中执行的方法中的UI线程。这在他们的async / await示例here

中得到了证明

在以前/其他情况下,您必须编组回主(UI)线程以更新UI线程,或者等到完成并从共享状态的对象检索结果。由于您使用的是async / await,因此您可以不使用调度程序,并直接更新UI。