2010-11-19 78 views
4

我试图从我的wpf应用程序的web加载图像。从wpf/surface的web加载图像

这个想法如下: 当我点击一个按钮,弹出一个包含附加信息的弹出窗口。在这个弹出窗口中,我使用了一些来自网络的图片。

问题: 正在加载弹出窗口时,系统在等待图像时挂起。我绑定了 来自我的代码背后的图像。图像存储在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 2010-11-19 12:48:57

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

和ofcourse唐忘了在app.xaml中设置资源:

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

如果您有可以使用普通的HTTP URI,那么你可以直接设置源到被不客气公共Web服务器上可用的图像:

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

WPF会照顾下载吧 - 即使我不是100%确定,它甚至会异步执行。

当然你也可以使用数据绑定也这么做:

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

并在视图模型

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

非常感谢。清洁和简单,两年后工作。 – JoshVarty 2013-01-19 06:20:17