从后台工作者

时间:2015-09-17 14:21:50

标签: c# wpf multithreading mvvm datagrid

我有一个绑定到var Result_Full = new ObservableCollection<IP_DataRow>()的DatGrid。这是一个简单的类,包含几个字符串&amp;双变量。没什么难的。

我做的是,我读了一个Excel文件(使用Telerik RadSpreadProcessing),它将行解析到我的类中。我在一个线程上执行此操作,以便不阻止UI。我遇到了一些问题:

1)我不能在读取excel文件的长进程中使用ref关键字(因为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的我的Tab(我的DataGrid在不同的TabPage上)时,我尝试使用上面提到的代码将新项添加到集合中,它返回一个错误说:调用线程无法访问此对象,因为另一个线程拥有它。,这是相当奇怪的,因为 InvokeOnUIThread 只是{{1这应该是线程安全的吗?

任何帮助都将受到高度赞赏。

编辑:显示更多代码:

这是我从BackgroundWorker调用的过程:

Dispatcher.Invoke()

在这里你可以看到,我必须创建临时集合 tmpError,tmpFull ,我收集我的数据。在进程结束时,我手动将值复制到绑定到DataGrid的主集合中。我想改变这一点,这意味着在过程中将值复制到主集合(而不是临时集合),以便用户可以实时查看如何将值添加到集合中。

P.S.2: 因为我不明原因,我的 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; } 电话中出现了一个问题。用{strong>后,我从InvokeOnUIThread更改为App.Current.Dispatcher.Invoke(action);错误。不同的帖子拥有它已停止。

1 个答案:

答案 0 :(得分:5)

  1. 您可以使用BackgroundWorker而不是线程来报告进度。 Here是一个简单的教程
  2. 我认为简单地调用Dispatcher将使用上下文的线程,在您的情况下不是UI线程。请尝试使用Application.Current.Dispatcher
  3. 简而言之,我相信你应该做到以下几点:

    1. 在UI线程中创建公共ObservableCollection并将其绑定到DataGrid
    2. 创建后台工作程序。将报告设置为true。订阅ReportProgress和DoWork活动。
    3. 运行worker async
    4. 在DoWork处理程序中创建一个列表并读取一些值。当你达到一定数量时,让我们说一百个,调用(sender as BackgroundWorker).ReportProgress方法,传入你填充的这个集合的事件args。
    5. 在报告进度处理程序中,从您通过事件参数传递的列表中填充ObservableCollection。
    6. 重复步骤4 - 5直到一切都完成