2016-01-20 149 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; 
}