从后台Worker更新ObservableCollection

本文关键字:ObservableCollection 更新 Worker 后台 | 更新日期: 2023-09-27 18:13:06

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

我所做的是,我读一个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(我的DataGrid在不同的TabPage上)的选项卡时,我尝试使用上述代码向集合添加新项目,它返回一个错误说:调用线程无法访问此对象,因为不同的线程拥有它。,这是相当奇怪的,因为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);错误与..不同的线程拥有它停止

从后台Worker更新ObservableCollection

  1. 你可以使用BackgroundWorker而不是thread来报告进度。这是一个简单的教程
  2. 我相信简单地调用Dispatcher将使用上下文的线程,在您的情况下不是ui线程。试试Application.Current.Dispatcher代替

总之,我认为你应该这样做:

  1. 在UI-thread中创建公共ObservableCollection并将其绑定到DataGrid
  2. 创建后台工作器。将报告设置为true。订阅ReportProgress和DoWork事件
  3. 运行worker async在DoWork处理程序中创建一个列表并读取一些值到它。当您达到一定数量时,假设有100个,调用(sender as BackgroundWorker).ReportProgress方法,将您已填充的集合传递给事件参数。
  4. 在报告进度处理程序中,从你通过事件参数传递的列表中填充你的ObservableCollection。
  5. 步骤4 - 5重复,直到所有操作完成