2015-09-17 57 views
6

我有一個DatGrid,它綁定到var Result_Full = new ObservableCollection<IP_DataRow>()。這是一個簡單的類,包含幾個字符串&雙變量。沒什麼困難。從後臺更新ObservableCollection工作人員

我所做的是,我讀了一個Excel文件(使用Telerik RadSpreadProcessing),它將行分析到我的類中。我在一個線程上這樣做,以便UI不被阻塞。我遇到了一些問題,但:

1)我不能使用ref關鍵字在一個很長的過程中讀取excel文件(因爲Result_Full是綁定到DataGrid的公共屬性),但我必須創建臨時ObservableCollection<IP_DataRow>(),其中值被放置。一旦這個過程完成後我運行下面的腳本複製值:

 foreach (var item in tmpFull) 
     { 
      InvokeOnUIThread(() => 
      { 
       Result_Full.Add(item); 
      }); 
     } 

我想什麼做的,是能夠在實時(如果可能的話)的項目是如何被加入到看我的DataGrid中的集合。

由於我使用.NET 4.5我試圖執行BindingOperations.EnableCollectionSynchronization這已在一些其他職位的建議,但我無法弄清楚如何我的UI鮑爾德收集Result_Full綁定到臨時使用的一個過程。

2)即使使用當前設置,當(在我的UI下)我移動到包含DataGrid(我的DataGrid在不同的TabPage上)的Tab中,並且嘗試使用上面提到的將新項添加到集合中代碼,它返回一個錯誤說:調用線程不能訪問此對象,因爲不同的線程擁有它。,這很奇怪,因爲InvokeOnUIThread沒有別的,只有Dispatcher.Invoke(),應該是線程安全的?

任何幫助將不勝感激。

編輯:顯示更多的代碼:

這是我從BackgroundWorker的調用過程:

public void ProcessFile() 
    { 
     var tmpError = new ObservableCollection<IP_DataRow>(); 
     var tmpFull = new ObservableCollection<IP_DataRow>(); 

     var _reader = new IP_ExcelReader(sExcelPath, ref tmpError, ref tmpFull); 
     string sResult = _reader.ReadExcelFile(); 
     if (sResult != string.Empty) 
     { 
      System.Windows.MessageBox.Show("Error processing selected Excel File!" + Environment.NewLine + Environment.NewLine + "Error message:" + Environment.NewLine + sResult); 
     } 

     foreach (var item in tmpError)//populates error list 
     { 
      IP_InvokeOnUIThread(() => 
      { 
       Result_Error.Add(item); 
      }); 
     } 

     foreach (var item in tmpFull)//populates full list 
     { 
      IP_InvokeOnUIThread(() => 
      { 
       Result_Full.Add(item); 
      }); 
     } 

     OnPropertyChanged("Result_Full"); 
     //OnPropertyChanged("Result_Error"); 

     iSelectedTabIndex = 1; 

    } 

在這裏你可以看到,我必須創建臨時收集tmpError,tmpFull在那裏我收集我的數據。在過程結束時,我手動將值複製到綁定到DataGrid的主集合中。我想對此進行更改,這意味着在過程中將值複製到主集合(不是臨時集合),以便用戶可以實時查看向集合中添加值的方式。

P.S.2: 因爲我不知道的原因,其中一個問題在我的InvokeOnUIThread調用中。一旦我從App.Current.Dispatcher.Invoke(action);更改爲App.Current.Dispatcher.BeginInvoke(action);錯誤..不同線程擁有它停止。

+0

哪個線程擁有'item'和'tmpFull'? – Pieter21

+0

*哪個調度程序?* Dispatcher.Current保存在TLS中,因此每個線程都有自己的調度程序。您需要訪問UI線程的調度程序。 – Will

+0

我正在使用** App.Current.Dispatcher.Invoke(action); **。我雖然這是UI調度員?那麼我如何訪問它? –

回答

5
  1. 您可以使用BackgroundWorker而不是線程來報告進度。 Here是一個簡單的教程
  2. 我相信,簡單地調用Dispatcher將使用上下文的線程,這不是UI線程在你的情況。嘗試Application.Current.Dispatcher代替

總之,我相信你應該做到以下幾點:

  1. 創建UI線程公衆的ObservableCollection並將其綁定到數據網格
  2. 創建一個後臺工作。將報告設置爲true。訂閱ReportProgress和DoWork事件。
  3. 運行人員異步
  4. 在DoWork處理程序中創建一個列表並向其中讀取一定數量的值。當你達到一定數量時,比如說一百,請撥打(sender as BackgroundWorker).ReportProgress方法,傳入你已經填充的這個集合的事件參數。
  5. 在報告進度處理程序中,從您通過事件參數傳遞的列表填充ObservableCollection。
  6. 重複步驟4 - 5,直到完成所有工作
+0

我已經在使用後臺工作人員。我遇到的問題是,我不知道如何將我的臨時集合與綁定到DataGrid的集合連接起來?這意味着,我只填寫我的價值觀,一旦我的Excel閱讀無效完成。我將分享更多代碼 –

+0

我最終將BackgroundWorker作爲ref參數傳遞給了我的Excel讀取函數,並且在那裏我調用了ProcessChanged方法,它實現了這個訣竅! –