Download image from network to wpf / surface

I am trying to download images from the internet in my wpf application.

The idea is this: When I click the button, a popup window appears with additional information. In this popup, I use some images from the Internet.

Problem: When the pop-up window loads, the systems freeze while waiting for images. I am linking images from my code. Images are saved in an ObservableCollection. I tried using the stream to load images, but every time I throw an exception saying that the stream does not own the object.

I tried using Invoke to load the downloaded images into UserinterfaceThread, but I cannot reach it. My code is as follows:

IList<Image> imagesFromWeb = downloadImagesFromWeb(url); DispatcherHelper.UIDispatcher.Invoke(DispatcherPriority.Normal, (ThreadStart)delegate() { foreach (Image img in imagesFromWeb { this.ObservableCollection_Images.Add(img); } } 

As soon as the images load and it tries to add the images to the popup window (already open), I get an exception saying the stream does not own the object

Can someone point me in the right direction?

+4
source share
3 answers

If you have an image available on a public web server that can be addressed using a normal HTTP-URI, you can directly set the source:

 <Image Source="http://www.someserver.com/myimage.png" /> 

WPF will take care of loading it - it will even do it asynchronously, I think, although I'm not 100% sure.

You can, of course, do this with data binding:

 <Image Source="{Binding TheImage}" /> 

And in viewmodel

 public string TheImage { get { return "http://www.someserver.com/myimage.png"; } } 
+10
source

You can get a lot of problems with collections, WPF, binding and thread

It’s best (in my opinion) to use a surveillance-safe dispatch collection

an implementation is implemented here that also includes thread safety:

 public class SafeObservable<T> : IList<T>, INotifyCollectionChanged, INotifyPropertyChanged { private readonly IList<T> collection = new List<T>(); private readonly Dispatcher dispatcher; public event NotifyCollectionChangedEventHandler CollectionChanged; public event PropertyChangedEventHandler PropertyChanged; private readonly ReaderWriterLock sync = new ReaderWriterLock(); public SafeObservable() { dispatcher = Dispatcher.CurrentDispatcher; } public void Add(T item) { if (Thread.CurrentThread == dispatcher.Thread) DoAdd(item); else dispatcher.BeginInvoke((Action)(() => DoAdd(item))); if (PropertyChanged != null) PropertyChanged(this, new PropertyChangedEventArgs("Count")); } private void DoAdd(T item) { sync.AcquireWriterLock(Timeout.Infinite); collection.Add(item); if (CollectionChanged != null) CollectionChanged(this, new NotifyCollectionChangedEventArgs(NotifyCollectionChangedAction.Add, item)); sync.ReleaseWriterLock(); } public void Clear() { if (Thread.CurrentThread == dispatcher.Thread) DoClear(); else dispatcher.BeginInvoke((Action)(DoClear)); if (PropertyChanged != null) PropertyChanged(this, new PropertyChangedEventArgs("Count")); } private void DoClear() { sync.AcquireWriterLock(Timeout.Infinite); collection.Clear(); if (CollectionChanged != null) CollectionChanged(this, new NotifyCollectionChangedEventArgs(NotifyCollectionChangedAction.Reset)); sync.ReleaseWriterLock(); } public bool Contains(T item) { sync.AcquireReaderLock(Timeout.Infinite); var result = collection.Contains(item); sync.ReleaseReaderLock(); return result; } public void CopyTo(T[] array, int arrayIndex) { sync.AcquireWriterLock(Timeout.Infinite); collection.CopyTo(array, arrayIndex); sync.ReleaseWriterLock(); } public int Count { get { sync.AcquireReaderLock(Timeout.Infinite); var result = collection.Count; sync.ReleaseReaderLock(); return result; } } public bool IsReadOnly { get { return collection.IsReadOnly; } } public bool Remove(T item) { if (Thread.CurrentThread == dispatcher.Thread) return DoRemove(item); var op = dispatcher.BeginInvoke(new Func<T, bool>(DoRemove), item); if (op == null || op.Result == null) return false; if (PropertyChanged != null) PropertyChanged(this, new PropertyChangedEventArgs("Count")); return (bool)op.Result; } private bool DoRemove(T item) { sync.AcquireWriterLock(Timeout.Infinite); var index = collection.IndexOf(item); if (index == -1) { sync.ReleaseWriterLock(); return false; } var result = collection.Remove(item); if (result && CollectionChanged != null) CollectionChanged(this, new NotifyCollectionChangedEventArgs(NotifyCollectionChangedAction.Reset)); sync.ReleaseWriterLock(); return result; } public IEnumerator<T> GetEnumerator() { return collection.GetEnumerator(); } System.Collections.IEnumerator System.Collections.IEnumerable.GetEnumerator() { return collection.GetEnumerator(); } public int IndexOf(T item) { sync.AcquireReaderLock(Timeout.Infinite); var result = collection.IndexOf(item); sync.ReleaseReaderLock(); return result; } public void Insert(int index, T item) { if (Thread.CurrentThread == dispatcher.Thread) DoInsert(index, item); else dispatcher.BeginInvoke((Action)(() => DoInsert(index, item))); if (PropertyChanged != null) PropertyChanged(this, new PropertyChangedEventArgs("Count")); } private void DoInsert(int index, T item) { sync.AcquireWriterLock(Timeout.Infinite); collection.Insert(index, item); if (CollectionChanged != null) CollectionChanged(this, new NotifyCollectionChangedEventArgs(NotifyCollectionChangedAction.Add, item, index)); sync.ReleaseWriterLock(); } public void RemoveAt(int index) { if (Thread.CurrentThread == dispatcher.Thread) DoRemoveAt(index); else dispatcher.BeginInvoke((Action)(() => DoRemoveAt(index))); if (PropertyChanged != null) PropertyChanged(this, new PropertyChangedEventArgs("Count")); } private void DoRemoveAt(int index) { sync.AcquireWriterLock(Timeout.Infinite); if (collection.Count == 0 || collection.Count <= index) { sync.ReleaseWriterLock(); return; } collection.RemoveAt(index); if (CollectionChanged != null) CollectionChanged(this, new NotifyCollectionChangedEventArgs(NotifyCollectionChangedAction.Reset)); sync.ReleaseWriterLock(); } public T this[int index] { get { sync.AcquireReaderLock(Timeout.Infinite); var result = collection[index]; sync.ReleaseReaderLock(); return result; } set { sync.AcquireWriterLock(Timeout.Infinite); if (collection.Count == 0 || collection.Count <= index) { sync.ReleaseWriterLock(); return; } collection[index] = value; sync.ReleaseWriterLock(); } } } 
+1
source

I thought the best way to upload an image.

Instead of snapping to an image in the code behind it, it is better to snap to a line containing the location of the image. After that, I use a converter in xaml code that converts the string to an image. (image loader is now inside the converter class)

code in xaml:

 <Image Source="{Binding imageUrl, Converter={StaticResource url}}" Height="200" Width="200"></Image> 

Converter Code:

 class ImageDownloader : IValueConverter { public object Convert(object value, Type targetType, object parameter, System.Globalization.CultureInfo culture) { string url =(string)value; return getImage(url); 
  } private object getImage(string imagefile) { /// IMPLEMENT FUNCTION TO DOWNLOAD IMAGE FROM SERVER HERE } public object ConvertBack(object value, Type targetType, object parameter, System.Globalization.CultureInfo culture) { return null; } } 

code>

and of course, don't forget to configure the resource in app.xaml with:

 <Application.Resources> <ResourceDictionary> <namespace:ImageDownloader x:Key="ImageDownloader" /> </ResourceDictionary> </Application.Resources> 
+1
source

All Articles