2012-02-25 7 views
7

markzを4番目の人物とするFacebookの最初の1000人を示す次のサンプルXAMLファイルを検討してください。これは単なるサンプルであることに注意してください。 1000要素のウィンドウは、どのように構築しても、良いデモンストレーションです。<Image Source = '...'>が遅いのはなぜですか?それについて何ができますか?

<Window x:Class="SO.MainWindow" 
     xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation" 
     xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml" 
     xmlns:clr="clr-namespace:System;assembly=mscorlib" 
     Title="MainWindow" Height="350" Width="525"> 
    <ListBox ItemsSource="{Binding}"> 
     <ListBox.ItemTemplate> 
      <DataTemplate> 
       <Image Source="{Binding}" /> 
      </DataTemplate> 
     </ListBox.ItemTemplate> 
    </ListBox> 
</Window> 

そして、背後にあるコード:非常に合理的なデスクトップおよび高速接続で

public partial class MainWindow : Window 
{ 
    public MainWindow() { 
     InitializeComponent(); 
     string[] urls = new string[1000]; 
     for (int i = 0; i < 1000; ++i) { 
      urls[i] = "http://graph.facebook.com/" + i + "/picture"; 
     } 
     this.DataContext = urls; 
    } 
} 

、プログラムは非常に遅いです。 ScrollBarでスクロールしようとしています...中央に向かって、30秒かかるでしょう。 「ホーム」キーと「終了」キーを押すとかなりの時間がかかります。

これは初回のみの画像取得の問題ではありません。すでに表示されている画像を前後に移動して見るのがやや速いが、一般的には非常に遅い。キャッシュには何も格納されていないように見えます。アプリケーションを閉じて再起動すると、すべてが遅くなります。

同等のHTMLコードが高速でブリーチングしています。いくつかの遅さは初めてですが、すべてが非常に高速です。

何が起こっているのですか?要素はキャッシングをまったく使用していますか?リストは現在提示されていないイメージのプリフェッチを行いますか?とにかくそれを言うようになっていますか?私の唯一の解決策は、キャッシュとプリフェッチロジックと共に、ビットマップオブジェクトを自分で管理することですか?もしそうなら、私が取り入れることができる以前の作品はどれですか?

EDIT(要約):H.B @

  1. 。仮想化をオフにする答えはあなたに最高の結果を与えるでしょう。リストボックス全体が、ウィンドウがロードされ、画像が再計算されなくなるとレンダリングされます。
  2. @Philコードはうまく動作し、特に前後に移動するときにパフォーマンスが向上します。
  3. 追加コードがない場合、WPFは呼び出しの間にイメージをキャッシュしません。 WinINETキャッシュはではなく、が使用されています。リクエストはHTTPヘッダーにCache命令が付属していますが、WPFは何もしません。

答えて

6

ListBoxesデフォルトでアイテムを仮想化するため、スクロールするとそのアイテムがオンザフライで作成されます。最初に画像をダウンロードし、それをデコードします。すべての画像をスクロールした場合、キャッシュされる可能性がありますが、ListBoxはまだImageのコントロールを再作成するため、毎回画像を再度デコードする必要があります。

あなたはその後、すべてがすぐにロードされます、またはあなたがRecyclingVirtualizationModeを変更することができ、その後、Images(およびListBoxItemsを含む)は一度捨てられないであろうListBoxfalseVirtualizingStackPanel.IsVirtualizing attached propertyを設定することで、仮想化をオフにすることができ作成した。

+0

ありがとうございましたH.B. +1して受け入れる。 – Uri

3

画像を1回だけダウンロードできるように、独自の画像キャッシュを追加する方法もあります。私の例を使用して

次のクラスは、URLを格納し、Imageプロパティに最初にアクセスしたときにイメージをダウンロードします

this.DataContext = new ViewModel(); 

あなたのコンストラクタでこれを入れてしまうでしょう。ここで

public class CachingImage 
{ 
    private readonly Uri _uri; 
    public CachingImage(string uriString) 
    { 
     _uri = new Uri(uriString, UriKind.RelativeOrAbsolute); 
    } 

    private BitmapImage _image; 

    public ImageSource Image 
    { 
     get 
     { 
      if (_image == null) 
      { 
       _image = new BitmapImage(_uri); 
       _image.DownloadCompleted += (sender, args) => ((BitmapImage)sender).Freeze(); 
      } 

      return _image; 
     } 
    } 
} 

は、ビューモデル

public class ViewModel 
{ 
    public ViewModel() 
    { 
     Images = Enumerable.Range(1, 1000).Select(i => new CachingImage("http://graph.facebook.com/" + i + "/picture")); 
    } 

    public IEnumerable<CachingImage> Images { get; private set; } 
    ... 

だともちろん、あなたのXAMLを変更する必要がありますわずか

<ListBox ItemsSource="{Binding}"> 
    <ListBox.ItemTemplate> 
     <DataTemplate> 
      <Image Source="{Binding Image}" /> 
     </DataTemplate> 
    </ListBox.ItemTemplate> 
</ListBox> 
+1

ありがとうございます@Phil。 +1。それは受け入れのための緊急の呼び出しでした。 – Uri

関連する問題