이미지를 표시하기 위해 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 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
와 충돌 :
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;
};
마지막으로 여기에 "정리"코드입니다. 방법 VirtualizingStackPanel_CleanUpVirtualizedItemEvent_1
은 ListBox
이 스크롤 될 때 regulary (예 : 2 또는 3 개의 목록 상자 항목마다)라고합니다.
이 샘플 코드의 문제점은 무엇입니까?
메모리가 해제되지 않는 이유는 무엇입니까?
'Picture' 란 무엇이고'GetImage()'메소드는 무엇을합니까? 당신은'_bitmap' 필드를'null'로 설정 만하지만'_picture' 필드는 남겨져 있습니다, 어떤 데이터를 보유하고있는 객체일까요? 또한 필드를 공개적으로 노출하는 것은 좋지 않습니다. 'PreviewImageItem'에'IDisposable'을 구현하고'VirtualizingStackPanel_CleanUpVirtualizedItemEvent_1' 메쏘드에서'Dispose()'를 호출하십시오 ... – khellang
정리에서'_picture' 속성도 무효화해야합니다. –
그림 형식이 "Microsoft.Xna"입니다. Framework.Media.Picture "와 많은 메모리를 필요로하지 않습니다. 대부분의 메모리는 Picture 객체가 제공하는 스트림에서 생성 된 BitmapImages에 사용됩니다. – Hyndrix