2016-01-20 144 views
0

我有WPF应用程序。在WPF中停止后台工作

在页面我有这样的时显示PanelLoadingtrue

<Grid Panel.ZIndex="1000" HorizontalAlignment="Stretch" Grid.RowSpan="3" Visibility="{Binding PanelLoading, Converter={StaticResource BoolToVis}}"> 
     <controls:LoadingPanel x:Name="loadingPanel" VerticalAlignment="Stretch" 
        IsLoading="{Binding PanelLoading}" 
        Message="Wait" 
        SubMessage="a minute" 
           /> 
    </Grid> 

在这个页面上“忙指示器”控制我也有其他控件(文本框,组合框等)

向的ItemsSource我绑定像一些值:

public string SearchWord 
    { 
     get { return _searchWord; } 
     set 
     { 
      _searchWord = value; 
      OnPropertyChanged("SearchWord"); 
      RunFilterWorker(); 
     } 
    } 

在上面的例子中RunFilterWorker将尝试运行前夕ry在textBox中更改文本的时间。

RunFilterWorker是一种创建BW并运行它的方法。

private void RunFilterWorker() 
    { 
     if (_filterWorker == null) 
     { 
      _filterWorker = CreateBackgroundWorker();//create if null (only on start) 
     } 
     else 
     { 
      if(_filterWorker.IsBusy)return; //do nothing if busy 
     } 

     _filterWorker.RunWorkerAsync(); 
    } 

     private BackgroundWorker CreateBackgroundWorker() 
    { 
     var bw = new BackgroundWorker(); 
     bw.WorkerSupportsCancellation = true; 
     bw.DoWork += filterWorker_DoWork; 
     bw.RunWorkerCompleted += filterWorker_CompleteWork; 
     return bw; 
    } 

对此BW我绑定在DoWork处理程序和RunWorkerCompleted

 private async void filterWorker_DoWork(object sender, DoWorkEventArgs e) 
    { 
     PanelLoading = true; 
     var products = await FilterProducts(); 
     e.Result = products; 
    } 

    private void filterWorker_CompleteWork(object sender, RunWorkerCompletedEventArgs e) 
    { 
     if (e.Error == null) 
     { 
      if (e.Cancelled) return; 
      var products = (e.Result) as List<ProductDTO>; 
      Products = products; 
      PanelLoading = false; 
     } 
     else 
     { 
      LogHelper.Log(e.Error); 
     } 
    } 

所以,当BW开始他的工作 - PanelLoading设置为true BusyIndi​​cator控件和显示。但在Complete没有发生与指标,它仍然在旋转。我相信这不是指标控制问题,而是BW。


要@Servy:

private void filterWorker_CompleteWork(object sender, RunWorkerCompletedEventArgs e) 
    { 
     PanelLoading = false; 
     if (e.Error == null) 
     { 
      if (e.Cancelled) return; 
      var products = (e.Result) as List<ProductDTO>; 
      Products = products; 
     } 
     else 
     { 
      LogHelper.Log(e.Error); 
     } 
    } 

不帮忙,不隐藏指示灯。

+0

你的代码应该按预期工作 - 你测试了你的loadPanel吗?我将测试以下内容:将PanelLoading设置为true,然后使用DispatcherTimer将PanelLoading设置回false(完全没有bgw) –

+0

@PhilipW,使用DispatcherTimer繁忙指示器也不能按预期工作。所以会试图找到控制问题)) – demo

回答

1

如果BGW没有错误且未取消,则您只能到达行PanelLoading = false;。但那不是你想要的行为。无论BGW为什么停止,您都希望加载面板消失,所以您的程序逻辑需要反映这一点。

您只需将该行移动到完成的处理函数的开头。


您还有另一个不相关的问题。你正在混合和匹配async与BackgroundWorker,你真的不应该。 BGW预计DoWork处理程序是同步方法。一旦它完成执行处理程序,它就会标记为已完成,但是你正在做的是让你的处理程序不做任何事情,除非开始一些工作,并且该工作实际上并没有完成,直到处理程序结束。因此,在BGW完成之后,您才能真正设置结果,直到

由于您已经有一个返回异步方法的Task,并且您可以使用async,所以完全使用BGW即可取消。这里什么都没有完成。制作RunFilterWorkerasync,让它处理任何抛出的错误,让它显示并隐藏加载面板等。

+0

@demo它有什么用处? – Servy

+0

嗯,它不利于隐藏我的繁忙指标 – demo

0

BGW是一个非常过时的技术,正如Servy正确指出的那样,它根本不理解async。给它一个async DoWork只是要求麻烦(特别是BGW在你期望的之前完成)。

我有一个博客系列,显示了如何Task.Run is superior to BGW,但在这种情况下,我会用Servy同意,你可能不需要BGW Task.Run。一个简单的Task应该就足够了:

Task _filterWorker; 
private void RunFilterWorker() 
{ 
    if (_filterWorker == null) 
    { 
    _filterWorker = FilterAsync(); 
    } 
} 

private Task FilterAsync() 
{ 
    PanelLoading = true; 
    try 
    { 
    Products = await FilterProducts(); 
    } 
    catch (Exception ex) 
    { 
    LogHelper.Log(ex); 
    } 
    PanelLoading = false; 

    // Ensure the calling method has set _filterWorker before we clear it. 
    await Task.Yield(); 
    _filterWorker = null; 
}