从后台工作更新的ObservableCollection [英] Update ObservableCollection from background Worker

查看:321
本文介绍了从后台工作更新的ObservableCollection的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我有一个DatGrid,这势必 VAR Result_Full =新的ObservableCollection< IP_DataRow>()。这是一个包含若干个串放一个简单的类;双变量。没有什么困难的。



我做的,是我读的Excel文件(Telerik的RadSpreadProcessing),它解析行到我的课堂。我这样做的一个线程,这样用户界面不会被阻断。我也遇到了一些问题,但:



1)在相当长的过程,读取Excel中我不能使用 REF 关键字文件(因为Result_Full是绑定到一个DataGrid公共财产),但我必须创建临时的ObservableCollection< IP_DataRow>(),其中的值放置。一旦这个过程完成后我运行下面的脚本复制值:

 的foreach(在tmpFull VAR项)
{
InvokeOnUIThread(()=>
{
Result_Full.Add(项目);
});
}

我想什么做的,就是能看到在实时(如果可能)的项目是如何被添加到集合在我的DataGrid中。



由于我使用.NET 4.5我试图执行 BindingOperations.EnableCollectionSynchronization 这已在一些其他职位的建议,但我无法弄清楚如何我的UI鲍尔德收集的 Result_Full 绑定到一个临时使用流程。



2)即使当前的设置,当(我的用户界面下),我移动到我的选项,其中包含的DataGrid(我的DataGrid是在不同的TabPage)和我尝试新的项目加入到与上述代码的集合,它会返回一个错误说:调用线程不能因为不同的线程拥有它访问该对象,这是相当奇怪的,因为<。 STRONG> InvokeOnUIThread 不是别的, Dispatcher.Invoke(),这应该是线程安全的?



任何帮助将高度赞赏



编辑:显示更多的代码:



这是这个过程中我打电话从BackgroundWorker的:

 公共无效ProcessFile()
{
变种tmpError =新的ObservableCollection< IP_DataRow>( );
变种tmpFull =新的ObservableCollection< IP_DataRow>();

变种_reader =新IP_ExcelReader(sExcelPath,楼盘tmpError,裁判tmpFull);
串sResult = _reader.ReadExcelFile();
如果(sResult!=的String.Empty)
{
System.Windows.MessageBox.Show(选择Excel文件错误处理!+ Environment.NewLine + Environment.NewLine +错误信息:+ Environment.NewLine + sResult);
}

的foreach(在tmpError VAR项目)//填充错误列表
{
IP_InvokeOnUIThread(()=>
{
Result_Error.Add(项目);
});
}

的foreach(在tmpFull VAR项目)//填充完整列表
{
IP_InvokeOnUIThread(()=>
{
Result_Full.Add(项目);
});
}

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

iSelectedTabIndex = 1;

}



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



PS2:
为UKNOWN理由给我,其中一个问题在我的 InvokeOnUIThread 通话撒谎。有一次,我从 App.Current.Dispatcher.Invoke(动作)改变; App.Current.Dispatcher.BeginInvoke(动作); 错误是 ..不同的线程拥有它停止。


解决方案

  1. 您可以使用BackgroundWorker的,而不是线程,因为它去报告进度。
    这里是一个简单的教程

  2. 我认为,简单地调用调度员将使用一种背景下,这是不是UI线程在你的案件线索。尝试 Application.Current.Dispatcher 而不是



在总之,我相信你应该请执行以下操作:




  1. 在UI线程创建公共的ObservableCollection并将其绑定到数据网格

  2. 创建后台工作。设置为true报告。订阅ReportProgress和DoWork的事件。

  3. 运行工人异步

  4. 在DoWork的处理程序创建一个列表,且读取值的一定量的它。当你到达一定量,比方说百,通话(发件人为BackgroundWorker的).ReportProgress 方法,在事件参数传递这个集合已填充。

  5. 在报告进度处理程序中,你已经通过throught事件参数列表填充您的ObservableCollection

  6. 步骤4 - 5被重复,直到一切都做


I have a DatGrid, which is bound to var Result_Full = new ObservableCollection<IP_DataRow>(). This is a simple class containing several string & double variables. Nothing difficult.

What I do, is that I read an Excel File (with Telerik RadSpreadProcessing), which parses rows into my class. I do this on a thread so that the UI is not blocked. I have encountered a few problems though:

1) I cannot use ref keyword in a long process which reads excel file (because Result_Full is a public property bound to a DataGrid), but I have to create temporary ObservableCollection<IP_DataRow>(), where the values are placed. Once the process has finished I run the following script for copying the values:

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

What I would like to do, is to be able to see in a real time (if possible) how items are being added to the collection in my DataGrid.

As I am using .Net 4.5 I tried to implement BindingOperations.EnableCollectionSynchronization as was suggested by some other post, yet I could not figure out how to bind my UI bould collection Result_Full to temporary used in a process.

2) Even with the current setup, when (under my UI) I move to my Tab which contains DataGrid (my DataGrid is on a different TabPage), and I try to add new item to the collection with the above mentioned code, it returns an error saying: The calling thread cannot access this object because a different thread owns it., which is rather weird, as InvokeOnUIThread is nothing else but Dispatcher.Invoke(), which should be thread safe?

Any help would be highly appreciated.

EDIT: Showing more code:

This is the process I call from 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;

    }

Here you can see, that I have to create temporary collection tmpError, tmpFull where I gather my data. At the end of process, I manually copy values into my main collections bound to DataGrid. I would like to change this, meaning that values are copied to the main collection (not temporary ones) during the process, so that user can see in a real time how values are added to the collection.

P.S.2: for uknown reason to me, one of the problems lied in my InvokeOnUIThread call. Once I changed from App.Current.Dispatcher.Invoke(action); to App.Current.Dispatcher.BeginInvoke(action); error with ..different thread owns it stopped.

解决方案

  1. You can use BackgroundWorker instead of thread, to report progress as it goes. Here is a simple tutorial
  2. I believe that simply calling Dispatcher will use thread of a context, which is not UI-thread in your case. Try Application.Current.Dispatcher instead

In short, I believe you should do the following:

  1. Create public ObservableCollection in UI-thread and bind it to DataGrid
  2. Create a background worker. Set reporting to true. Subscribe to ReportProgress and DoWork events.
  3. Run worker async
  4. In DoWork handler create a list and read some amount of values to it. As you reach some amount, let's say a hundred, call (sender as BackgroundWorker).ReportProgress method, passing in event args this collection you have populated.
  5. In report progress handler, populate your ObservableCollection from a list you've passed throught event args.
  6. Steps 4 - 5 are repeated until everything is done

这篇关于从后台工作更新的ObservableCollection的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆