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.
Application.Current.Dispatcher
insteadIn short, I believe you should do the following:
(sender as BackgroundWorker).ReportProgress
method, passing in event args this collection you have populated.If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With