C# 在wpf/surface中从web加载图像

C# 在wpf/surface中从web加载图像,c#,wpf,multithreading,mvvm-light,pixelsense,C#,Wpf,Multithreading,Mvvm Light,Pixelsense,我正在尝试在wpf应用程序中从web加载图像 其思路如下: 当我点击一个按钮时,会弹出一个包含额外信息的弹出窗口。在这个弹出窗口中,我使用了一些来自web的图像 问题是: 加载弹出窗口时,系统在等待图像时挂起。我正在装订 我的代码背后的图像。图像存储在一个可观察的集合中。我试过了 使用线程加载图像,但每次我都会遇到一个异常,说线程不是对象的所有者 我尝试使用调用将下载的图像获取到UserinterfaceThread,但无法访问它。我的代码如下: IList<Image&g

我正在尝试在wpf应用程序中从web加载图像

其思路如下: 当我点击一个按钮时,会弹出一个包含额外信息的弹出窗口。在这个弹出窗口中,我使用了一些来自web的图像

问题是: 加载弹出窗口时,系统在等待图像时挂起。我正在装订 我的代码背后的图像。图像存储在一个可观察的集合中。我试过了 使用线程加载图像,但每次我都会遇到一个异常,说线程不是对象的所有者

我尝试使用调用将下载的图像获取到UserinterfaceThread,但无法访问它。我的代码如下:

        IList<Image> imagesFromWeb = downloadImagesFromWeb(url);


        DispatcherHelper.UIDispatcher.Invoke(DispatcherPriority.Normal, (ThreadStart)delegate()
        {
            foreach (Image img in imagesFromWeb 
            {
                this.ObservableCollection_Images.Add(img);
            }
    }
IList imagesFromWeb=下载imagesFromWeb(url);
DispatcherHelper.UIDispatcher.Invoke(DispatcherPriority.Normal,(ThreadStart)delegate()
{
foreach(来自Web的图像中的图像img
{
这个.observeCollection_Images.Add(img);
}
}
一旦图像被下载并且它试图将图像添加到(已经打开的)弹出窗口中,我就会得到一个异常,说是线程 不是对象的所有者


有人能给我指出正确的方向吗?

您可以在集合、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();
        }
    }
}
公共类安全可观察:IList、INotifyCollectionChanged、INotifyPropertyChanged
{
私有只读IList集合=新列表();
专用只读调度器;
公共事件通知CollectionChangedEventHandler CollectionChanged;
公共事件属性更改事件处理程序属性更改;
private readonly ReaderWriterLock sync=new ReaderWriterLock();
公众安全观察()
{
dispatcher=dispatcher.CurrentDispatcher;
}
公共作废新增(T项)
{
if(Thread.CurrentThread==dispatcher.Thread)
DoAdd(项目1);
其他的
dispatcher.BeginInvoke((操作)(()=>DoAdd(项目));
if(PropertyChanged!=null)
PropertyChanged(新PropertyChangedEventArgs(“计数”);
}
专用作废DoAdd(T项)
{
sync.AcquireWriterLock(Timeout.Infinite);
集合。添加(项目);
如果(CollectionChanged!=null)
收藏改变了(这个,
新的NotifyCollectionChangedEventArgs(NotifyCollectionChangedAction.Add,item));
sync.ReleaseWriterLock();
}
公共空间清除()
{
if(Thread.CurrentThread==dispatcher.Thread)
DoClear();
其他的
调度员开始呼叫((操作)(文档));
if(PropertyChanged!=null)
PropertyChanged(新PropertyChangedEventArgs(“计数”);
}
私有void DoClear()
{
sync.AcquireWriterLock(Timeout.Infinite);
collection.Clear();
如果(CollectionChanged!=null)
收藏改变了(这个,
新建NotifyCollectionChangedEventArgs(NotifyCollectionChangedAction.Reset));
sync.ReleaseWriterLock();
}
公共布尔包含(T项)
{
sync.eaderlock(Timeout.Infinite);
var结果=集合。包含(项);
sync.ReleaseReaderLock();
返回结果;
}
public void CopyTo(T[]数组,int arrayIndex)
{
sync.AcquireWriterLock(Timeout.Infinite);
collection.CopyTo(数组、数组索引);
sync.ReleaseWriterLock();
}
公共整数计数
{
得到
{
sync.eaderlock(Timeout.Infinite);
var result=collection.Count;
sync.ReleaseReaderLock();
返回结果;
}
}
公共图书馆是只读的
{
获取{return collection.IsReadOnly;}
}
公共布尔删除(T项)
{
if(Thread.CurrentThread==dispatcher.Thread)
返回DoRemove(项目);
var op=dispatcher.BeginInvoke(新函数(DoRemove),项);
if(op==null | | op.Result==null)
返回false;
if(PropertyChanged!=null)
PropertyChanged(新PropertyChangedEventArgs(“计数”);
返回(布尔)运算结果;
}
私人布尔多雷莫夫酒店(T项目)
{
sync.AcquireWriterLock(Timeout.Infinite);
var索引=集合。索引(项目);
如果(索引==-1)
{
sync.ReleaseWriterLock();
返回false;
}
var结果=收集。删除(项目);
if(result&&CollectionChanged!=null)
集合已更改(此,新
NotifyCollectionChangedEventArgs(NotifyCollectionChangedAction.Reset));
sync.ReleaseWriterLock();
返回结果;
}
公共IEnumerator GetEnumerator()
{
返回集合。GetEnumerator();
}
System.Collections.IEnumerator System.Collections.IEnumerable.GetEnumerator()
{
返回集合。GetEnumerator();
}
公共整数索引(T项)
{
sync.eaderlock(Timeout.Infinite);
var结果=collection.IndexOf(项目);
sync.ReleaseReaderLock();
返回结果;
}
公共空白插入(整数索引,T项)
{
if(Thread.CurrentThread==dispatcher.Thread)
DoInsert(索引,项目);
其他的
dispatcher.BeginInvoke((操作)(()=>DoInsert(索引,项));
if(PropertyChanged!=null)
PropertyChanged(新PropertyChangedEventArgs(“计数”);
}
私有void DoInsert(int索引,T项)
{
sync.AcquireWriterLock(Timeout.Infinite);
收藏。插入(索引,项目);
如果(CollectionChanged!=null)
收藏改变了(这个,
新的NotifyCollectionChangedEventArgs(NotifyCollectionChangedAction.Add、item、index));
<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;
    }
}
<Application.Resources>
   <ResourceDictionary>
       <namespace:ImageDownloader x:Key="ImageDownloader" />
   </ResourceDictionary>
</Application.Resources>
<Image Source="http://www.someserver.com/myimage.png" />
<Image Source="{Binding TheImage}" />
public string TheImage 
{ 
    get { return "http://www.someserver.com/myimage.png"; } 
}