画像を表示するためにListBox
を使用している私のカスタムギャラリーに、Windows Phone 8の写真フォルダに保存されているすべての画像を表示したいとします。ListBoxに画像があるときにOutOfMemoryExceptionが発生するのはなぜですか?
public class PreviewPictureConverter : System.Windows.Data.IValueConverter
{
public object Convert(object value, Type targetType, object parameter, System.Globalization.CultureInfo culture)
{
PreviewImageItem c = value as PreviewImageItem;
if (c == null)
return null;
return c.ImageData;
}
public object ConvertBack(object value, Type targetType, object parameter, System.Globalization.CultureInfo culture)
{
throw new NotImplementedException();
}
}
画像はカスタムクラスに格納されて :
class PreviewImageItem
{
public Picture _picture = null;
public BitmapImage _bitmap = null;
public PreviewImageItem(Picture pic)
{
_picture = pic;
}
public BitmapImage ImageData
{
get
{
System.Diagnostics.Debug.WriteLine("Get picture " + _picture.ToString());
_bitmap = new BitmapImage();
Stream data = _picture.GetImage();
try
{
_bitmap.SetSource(data); // Out-of memory exception (see text)
}
catch (Exception ex)
{
System.Diagnostics.Debug.WriteLine("Exception : " + ex.ToString());
}
finally
{
data.Close();
data.Dispose();
data = null;
}
return _bitmap;
}
}
}
次のコードが使用され、次のコンバータを
<phone:PhoneApplicationPage.Resources>
<MyApp:PreviewPictureConverter x:Key="PreviewPictureConverter" />
</phone:PhoneApplicationPage.Resources>
<ListBox Name="previewImageListbox" VirtualizingStackPanel.VirtualizationMode="Recycling">
<ListBox.ItemsPanel>
<ItemsPanelTemplate>
<VirtualizingStackPanel CleanUpVirtualizedItemEvent="VirtualizingStackPanel_CleanUpVirtualizedItemEvent_1">
</VirtualizingStackPanel>
</ItemsPanelTemplate>
</ListBox.ItemsPanel>
<ListBox.ItemTemplate>
<DataTemplate>
<Grid>
<Image Source="{Binding Converter={StaticResource PreviewPictureConverter}}" HorizontalAlignment="Center" VerticalAlignment="Center" />
</Grid>
</DataTemplate>
</ListBox.ItemTemplate>
</ListBox>
次のよう
ListBox
コードでありますListBox
データソースを設定する:
private List<PreviewImageItem> _galleryImages = new List<PreviewImageItem>();
using (MediaLibrary library = new MediaLibrary())
{
PictureCollection galleryPics = library.Pictures;
foreach (Picture pic in galleryPics)
{
_galleryImages.Add(new PreviewImageItem(pic));
}
previewImageListbox.ItemsSource = _galleryImages;
};
は最後にここで「クリーンアップ」コードです:
private void VirtualizingStackPanel_CleanUpVirtualizedItemEvent_1(object sender, CleanUpVirtualizedItemEventArgs e)
{
PreviewImageItem item = e.Value as PreviewImageItem;
if (item != null)
{
System.Diagnostics.Debug.WriteLine("Cleanup");
item._bitmap = null;
}
}
このすべてが正常に動作しますが、コードは、いくつかの画像(高速スクロール特に)の後OutOfMemoryException
でクラッシュ。 VirtualizingStackPanel_CleanUpVirtualizedItemEvent_1
は、ListBox
がスクロールされたときにregulary(例えば、2つまたは3つのリストボックスエントリごと)と呼ばれます。
このサンプルコードで何が問題になっていますか?
メモリが解放されないのはなぜですか(十分に速い)?
'Picture'とは何か、GetImage()メソッドは何をしていますか?あなたは '_bitmap'フィールドを' null'にセットするだけですが、 '_picture'フィールドは残されています。それは何らかのデータを保持するオブジェクトですか?また、フィールドを公開するのは良い方法ではありません。 'PreviewImageItem'に' IDisposable'を実装し、 'VirtualizingStackPanel_CleanUpVirtualizedItemEvent_1'メソッドで' Dispose() 'を呼び出してください... – khellang
クリーンアップでは、' _picture'プロパティも無効にする必要があります –
Pictureは "Microsoft.Xna"タイプです。 Framework.Media.Picture "と多くのメモリを必要としません。ほとんどのメモリは、ピクチャオブジェクトによって提供されるストリームから作成されるBitmapImagesによって使用されます。 – Hyndrix