Reputation: 259
I'm working on a C# WPF application which loads a lot of images and displays it as thumbnails. I'd like to do it in a multi-threaded way. Therefore I tried to implement a BackgroundWorker.
The code of the BackgroundWorker's DoWork():
string[] files = e.Argument as string[];
foreach (string file in files)
{
ImageModel image = new ImageModel();
image.FilePath = file;
_importWorker.ReportProgress(1, image);
_imageCollectionVM.Images.Add(image); // also tried this one in ReportProgress()
}
In my XAML code I bind to the BitmapImage property of ImageModel. (AsyncState=True doesn't help.) Here I get this error: "DependencySource" and "DependencyObject" have to be in the same thread.
<Image Source="{Binding BitmapImage}" />
If I comment this out, the image seems to be imported but I cannot access it, e.g. by selecting it in a ListView. In its SelectionChanged it says then that this object is possessed by another thread.
How do I solve these problems? Thanks in advance!
Upvotes: 4
Views: 7923
Reputation: 6636
You must marshall the update to the GUI to the main thread. Basically you can only multi-thread the loading of the images from disk, but the actual update of the GUI must be done single threaded.
There are many ways to do this, and many questions on stackoverflow address it. Here are a few to get you started
Update UI from background Thread
Update BindingList<> from a background Thread?
Is it evil to update a pictureBox from a background C# thread?
How to use a BindingList for this
How do you correctly update a databound datagridview from a background thread
Upvotes: 2
Reputation: 8162
In a similar situation i did the following:
let this ImageSource be Lazy
// // pseudocode here
Lazy lazy = new Lazy(imageProvider.LoadImage(this.imagePath))
// in the ImageViewModel ...
imageSource { get { return lazy.Value; } }
Upvotes: 0
Reputation: 3688
BackGround Worker is good imo for large tasks, but if it something simple like what you are doing I would prefer to do it like this
start with a list of Image
List<Image> Images =new List<Image>();
then run this
Task.Factory.StartNew( () =>
{
string[] files = e.Argument as string[];
foreach (string file in files)
{
ImageModel image = new ImageModel();
image.FilePath = file;
// _importWorker.ReportProgress(1, image);
this.BeginInvoke( new Action(() =>
{
Images.Add(image);
}));
}
});
No guarantee I have the right number of brackets in that code.
Upvotes: 1