2010-11-19 15 views
4

wpfアプリケーションでウェブから画像を読み込もうとしています。wpf/surfaceでウェブから画像を読み込む

考え方は次のとおりです。 ボタンをクリックすると、追加情報を含むポップアップが表示されます。このポップアップでは、Webからいくつかの画像を使用しています。

問題: ポップアップが読み込まれると、イメージを待っている間にシステムがハングします。私は束縛しています 私のコードの画像は背後にあります。イメージはObservableCollectionに格納されます。私は 画像を読み込むためのスレッドを使用してみましたが、スレッドがオブジェクトの所有者ではないという例外が発生するたびに実行されます。

私は、ダウンロードしたイメージをUserinterfaceThreadに取得するためにInvokeを使用しようとしましたが、私はそれに到達できません。私のコードは以下の通りです:

 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

ありがとう中:

もちろん、同様のデータバインディングでこれを行うことができます。私はすでに別の解決策を見つけたので、私はそれを使用しませんでした(下記参照)。 – 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のリソースを設定することを忘れないでください:

あなたは、通常のHTTP URIを使用してadressedできる公開Webサーバ上で利用可能なイメージを持っているなら、あなたはそれに直接ソースを設定することができます10
<Application.Resources> 
    <ResourceDictionary> 
     <namespace:ImageDownloader x:Key="ImageDownloader" /> 
    </ResourceDictionary> 
</Application.Resources> 
9

<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

ありがとうございます。クリーンでシンプルで、2年後に動作します。 – JoshVarty

関連する問題