2010-11-19 2 views
4

Я пытаюсь загрузить изображения из Интернета в приложении wpf.Загрузка изображения из сети в wpf/surface

Идея заключается в следующем: Когда я нажимаю на кнопку, всплывающее окно с дополнительной информацией поднимается. В этом всплывающем окне я использую некоторые изображения из Интернета.

Проблема: Когда всплывающее окно загружается, системы зависают во время ожидания изображений. Я привязываю к изображениям из моего кода. Изображения сохраняются в ObservableCollection. Я попробовал с помощью потока для загрузки изображений, но каждый раз, когда я запускаю исключение, говорящий, что поток не является владельцем объекта.

Я попытался использовать Invoke для загрузки загруженных изображений в UserinterfaceThread, но я не могу его достичь. Мой код выглядит следующим образом:

 IList<Image> imagesFromWeb = downloadImagesFromWeb(url); 


     DispatcherHelper.UIDispatcher.Invoke(DispatcherPriority.Normal, (ThreadStart)delegate() 
     { 
      foreach (Image img in imagesFromWeb 
      { 
       this.ObservableCollection_Images.Add(img); 
      } 
    } 

Как только изображения будут загружены, и пытается добавить изображения к (уже открыт) всплывающее окно, я получаю исключение заявив, что нить не является владельцем объекта

Может ли кто-нибудь указать мне направление вправо?

ответ

1

Вы можете получить целый ряд проблем с коллекциями, WPF, связыванием и нарезание резьб

Самым лучшим, что (на моем взгляде) является использованием диспетчера безопасного наблюдаемых коллекций

здесь является реализацией, с также включает защиту резьбы:

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(); 
     } 
    } 
} 
+0

Thanx для ответа. Я не использовал его, потому что уже нашел другое решение (см. Ниже). – Marcel

1

Я понял, что есть лучший способ загрузить изображение.

Вместо привязки к изображению в коде позади лучше привязываться к строке, содержащей местоположение изображения. После этого я использую конвертер в коде xaml, который преобразует строку в образ. (Загрузчик изображений теперь внутри класса преобразователя)

код в XAML:

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

Код для преобразователя:


    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; 
    } 
} 

и, конечно, дон Не забудьте настроить ресурс в app.xaml с помощью:

<Application.Resources> 
    <ResourceDictionary> 
     <namespace:ImageDownloader x:Key="ImageDownloader" /> 
    </ResourceDictionary> 
</Application.Resources> 
9

Если у вас есть изображение, доступных на общедоступном веб-сервере, который может быть адресован с помощью обычного HTTP URI, то вы можете установить источник непосредственно к тому, что:

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

WPF будет заботиться о его загрузку - Я даже сделаю это асинхронно, хотя я не уверен на 100%.

Конечно, Вы можете сделать это с помощью привязки данных, а также:

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

И в ViewModel

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

Большое вам спасибо. Чисто и просто и работает два года спустя. – JoshVarty

Смежные вопросы