我想在我的自定义库中ListBox显示Windows Phone 8照片文件夹中存储的所有图像,该文件夹用于显示图像。
ListBox
的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(); } }
图像存储在自定义类中:
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数据源:
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时,该方法称为常规(例如,每2或3个列表框条目)ListBox。
OutOfMemoryException
VirtualizingStackPanel_CleanUpVirtualizedItemEvent_1
此示例代码有什么问题?
为什么没有释放内存(足够快)?
哦,最近我整天杀了这个,使它正常工作!
因此解决方案是:
使您的图像控件免费资源。所以设置
BitmapImage bitmapImage = image.Source as BitmapImage; bitmapImage.UriSource = null; image.Source = null;
如前所述。
确保在列表的每个项目上虚拟化_bitmap。您应该按需加载它(LongListSelector.Realized方法),并且必须销毁它!它不会自动收集,并且GC.Collect也不能工作。空引用也不起作用:(但是这里是方法:制作1x1像素文件。将其复制到程序集中并从中获取资源流以处置1x1像素为空白的图像。将自定义处置方法绑定到LongListSelector.UnRealized事件(e。容器处理您的列表项)。
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的图片。
如果您错过了数据收集的第2步,则可以看到良好的结果,但是在滚动100-200个项目后内存溢出。