代码之家  ›  专栏  ›  技术社区  ›  Edword

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

  •  0
  • Edword  · 技术社区  · 8 年前

    我正在尝试实施 不确定进度条 到我的程序中。我不熟悉线程,但据我所知,这里最好的选择之一是添加一个异步方法,然后等待“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将其关闭,这不太好)。

    系统工作正常,时间框架方面一切正常,但加载条冻结,未显示进度。相同的LW栏在主窗口中使用类似的设置工作。我缺少了什么?提前谢谢!

    2 回复  |  直到 8 年前
        1
  •  1
  •   Stephen Cleary    8 年前

    据我所知,这里最好的选择之一是添加一个异步方法,然后等待“heavy”函数执行其结果

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

    目前的代码使用 任务.运行 移动到线程池,然后立即转身使用 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();
      }
    }
    
        2
  •  0
  •   xtreampb    8 年前

    不要使用您的调度程序。微软有远见,利用它的魔力(SynchronizationContext),能够在异步上下文中执行的方法中更新UI线程。这在找到的异步/等待示例中演示 here

    而在以前/其他情况下,您必须封送回主(UI)线程以更新UI线程,或者等到完成并从共享状态的对象中检索结果。因为您正在使用async/await,所以您应该可以不使用dispatcher,直接更新UI。