当我的列表框中有图像时,为什么会出现 OutOfMemoryException? [英] Why do I get an OutOfMemoryException when I have images in my ListBox?

查看:27
本文介绍了当我的列表框中有图像时,为什么会出现 OutOfMemoryException?的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我想在使用 ListBox 显示图像的自定义图库中显示存储在 Windows Phone 8 照片文件夹中的所有图像.

I want to display all images stored in the Windows Phone 8 photo folder in my custom gallery which uses a ListBox for displaying the images.

ListBox代码如下:

    <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>

使用以下转换器:

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();
    }
}

图像存储在自定义类中:

Images are stored in a custom class:

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;
        }
    }
}

以下代码用于设置ListBox数据源:

The following code is used to set the ListBox data source:

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(尤其是在快速滚动时).当 ListBox 滚动时,方法 VirtualizingStackPanel_CleanUpVirtualizedItemEvent_1 被定期调用(例如,每 2 或 3 个列表框条目).

All this works fine but the code crashes with an OutOfMemoryException after a few images (especially when scrolling fast). The method VirtualizingStackPanel_CleanUpVirtualizedItemEvent_1 is called regulary (e.g. every 2 or 3 listbox entries) when the ListBox is scrolled.

这个示例代码有什么问题?

What's wrong with this sample code?

为什么没有释放内存(足够快)?

Why is memory not freed (fast enough)?

推荐答案

哦,我最近为了让它工作而干了一整天!

Oh, I recently killed whole day to make this working!

所以解决方案是:

让您的图像控制免费资源.所以设置

Make your Image control free resources. So set the

BitmapImage bitmapImage = image.Source as BitmapImage;
bitmapImage.UriSource = null;
image.Source = null;

正如之前提到的.

确保在列表的每个项目上虚拟化 _bitmap.您应该按需加载它(LongListSelector.Realized 方法),并且必须销毁它!它不会自动收集并且 GC.Collect 也不起作用.空引用也不起作用:(但这里是方法:制作 1x1 像素文件.将其复制到程序集中并从中生成资源流,以使用 1x1 像素空白处理您的图像.将自定义处置方法绑定到 LongListSelector.UnRealized 事件(e.Container 处理您的列表项).

Make sure you virtualize _bitmap on every item of the list. You should load it on demand (LongListSelector.Realized method) and you have to destroy it! It won't going to collect automatically and GC.Collect doesn't work either. Null reference is not working too :( But here is the method: Make 1x1 pixel file. Copy it into assembly and make resource stream from it to dispose your images with 1x1 pixel blank. Bind custom dispose method to LongListSelector.UnRealized event (e.Container handles your list item).

public static void DisposeImage(BitmapImage image)
{
    Uri uri= new Uri("oneXone.png", UriKind.Relative);
    StreamResourceInfo sr=Application.GetResourceStream(uri);
    try
    {
        using (Stream stream=sr.Stream)
        {
            image.DecodePixelWidth=1; //This is essential!
            image.SetSource(stream);
        }
    }
    catch { }
}

在 LongListSelector 中为我工作,其中包含 1000 张图像,每个图像宽度为 400.

Working for me in LongListSelector with 1000 images 400 width each.

如果您错过了数据收集的第 2 步,您可以看到良好的结果,但在滚动 100-200 个项目后内存溢出.

If you miss the 2 step with the data collection you can see the the good results but the memory overflows after 100-200 items scrolled.

这篇关于当我的列表框中有图像时,为什么会出现 OutOfMemoryException?的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
相关文章
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆