2015-09-17 56 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方法,它实现了这个诀窍! –