具有网格视图的 UWP 应用程序在滚动时丢失图像
UWP App with Grid View Losing Images when scrolling
对 UWP 和 XAML 比较陌生,我不确定如何调试它。
我有一个基于 Template10 Hamburger 模板和 Template10 增量加载示例的 UWP 应用程序,以及来自示例照片查看器 (Windows 8: Making a Simple Photo Viewer in C# and XAML) 的一些位。
我修改了主页以显示来自图片文件夹的图像的网格视图,图像被递增加载。我还从示例照片查看器 (Windows 8: Making a Simple Photo Viewer in C# and XAML) 中提取了一些。
应用程序启动时,图像按预期显示,当我向下滚动时,图像按需加载和显示。问题是当我向上滚动列表时,图像不再显示。我的 gridview 项目仍然显示文件名和彩色项目背景,但不再绘制图像。
为了保持较小的内存占用,我没有将实际的位图图像存储为我的集合的一部分,而是存储了一个 StorageItemThumbnail。我最初只想存储图像路径,但这对图片库中的任何内容都不起作用。
public class Picture
{
public StorageItemThumbnail ImageThumbNail {get; set;}
public string Name {get; set;}
}
为了显示这个,我使用转换器 class 创建一个流来设置图像源:
public object Convert(object value, Type targetType, object parameter, string language)
{
BitmapImage image = null;
if (value != null)
{
if (value.GetType() != typeof(StorageItemThumbnail))
{
throw new ArgumentException("Expected a StorageItemThumbnail as binding input.");
}
if (targetType != typeof(ImageSource))
{
throw new ArgumentException("Expected ImageSource as binding output.");
}
if (Windows.ApplicationModel.DesignMode.DesignModeEnabled)
{
image = new BitmapImage();
image.UriSource = new Uri("ms-appx:///Assets/DesignModeThumbnailPlaceholder.png");
}
else
{
StorageItemThumbnail ThumbNailFile = (StorageItemThumbnail)value;
if (ThumbNailFile == null)
return image;
image = new BitmapImage();
IRandomAccessStream thumbnailStream = ThumbNailFile as IRandomAccessStream;
image.SetSource(thumbnailStream);
}
}
return (image);
}
并且在我的XAML中绑定如下:
<DataTemplate x:Name="PictureGridTemplate2">
<Grid Height="150" Width="150">
<Grid.RowDefinitions>
<RowDefinition Height="*" />
<RowDefinition Height="Auto" />
</Grid.RowDefinitions>
<Border Grid.RowSpan="2" Background="Black" Opacity="0.8" />
<Image Width ="130" HorizontalAlignment="Center"
Stretch="Uniform" Source="{Binding ImageThumbNail, Converter={StaticResource ThumbnailFileToImageSourceConverter}}"/>
<TextBlock Grid.Row="1" MaxHeight="30" Text="{Binding Name}"
Foreground="White" TextTrimming="CharacterEllipsis"/>
</Grid>
</DataTemplate>
任何人都可以指出我在这方面出错的方向吗?
雪莉
* 已解决 *
我终于弄清楚是什么导致了这个问题。
这是 gridview 虚拟化、我的数据模型以及我如何通过转换器提供图像的副作用。
作为测试,我删除了转换器,更改了我的数据模型以存储缩略图的 BitmapImage 实例(比存储整个图像小)并直接绑定到那个 属性。这有效,当我在 gridview 中上下滚动时,图像显示在屏幕上。
然后我更改了我的数据模型,使 BitmapImage 属性 getter return 从 StorageItemThumbnail 属性 动态构建 BitmapImage - 与使用时相同的问题转换器。
通过在 getter 中添加一些调试语句,我看到第二次请求时 BitmapImage 的高度和宽度为 0。啊哈!那为什么是 0?
在第二个请求中查看 StorageItemThumbnail 属性 我看到 Stream 位置在 EOF(不像第一个请求中的 0)——所以这解释了 0 的宽度和高度,这解释了屏幕上的空图像控件。
我更改了我的代码以使用 StorageItemThumbnail.CloneStream,现在显示了所有图像。
下面是转换方法:
public object Convert(object value, Type targetType, object parameter, string language)
{
BitmapImage image = null;
if (value != null)
{
if (value.GetType() != typeof(StorageItemThumbnail))
{
throw new ArgumentException("Expected a StorageItemThumbnail as binding input.");
}
if (targetType != typeof(ImageSource))
{
throw new ArgumentException("Expected ImageSource as binding output.");
}
if ((StorageItemThumbnail)value == null)
{
System.Diagnostics.Debug.WriteLine("Thumbnail is null.");
return image;
}
image = new BitmapImage();
using (var thumbNailClonedStream = ((StorageItemThumbnail)value).CloneStream())
{
System.Diagnostics.Debug.WriteLine("Setting image source from cloned stream.");
image.SetSource(thumbNailClonedStream);
}
}
return (image);
}
感谢所有花时间回答并帮助我指明正确方向的人。
您可以尝试使用已编译的绑定 x:Bind 而不是 Binding
在这种情况下,您的应用程序性能会更快。
分阶段优化您的数据模板以逐步更新 GridView 项目:
<Grid Height="150" Width="150">
<Grid.RowDefinitions>
<RowDefinition Height="*" />
<RowDefinition Height="Auto" />
</Grid.RowDefinitions>
<Border Grid.RowSpan="2" Background="Black" Opacity="0.8" />
<Image Width ="130" HorizontalAlignment="Center"
Stretch="Uniform" Source="{Binding ImageThumbNail, Converter={StaticResource ThumbnailFileToImageSourceConverter}}" x:Phase="2"/>
<TextBlock Grid.Row="1" MaxHeight="30" Text="{Binding Name}" x:Phase="1"
Foreground="White" TextTrimming="CharacterEllipsis"/>
</Grid>
阅读此主题:
ListView and GridView UI optimization
ListView and GridView data virtualization
对 UWP 和 XAML 比较陌生,我不确定如何调试它。
我有一个基于 Template10 Hamburger 模板和 Template10 增量加载示例的 UWP 应用程序,以及来自示例照片查看器 (Windows 8: Making a Simple Photo Viewer in C# and XAML) 的一些位。
我修改了主页以显示来自图片文件夹的图像的网格视图,图像被递增加载。我还从示例照片查看器 (Windows 8: Making a Simple Photo Viewer in C# and XAML) 中提取了一些。
应用程序启动时,图像按预期显示,当我向下滚动时,图像按需加载和显示。问题是当我向上滚动列表时,图像不再显示。我的 gridview 项目仍然显示文件名和彩色项目背景,但不再绘制图像。
为了保持较小的内存占用,我没有将实际的位图图像存储为我的集合的一部分,而是存储了一个 StorageItemThumbnail。我最初只想存储图像路径,但这对图片库中的任何内容都不起作用。
public class Picture
{
public StorageItemThumbnail ImageThumbNail {get; set;}
public string Name {get; set;}
}
为了显示这个,我使用转换器 class 创建一个流来设置图像源:
public object Convert(object value, Type targetType, object parameter, string language)
{
BitmapImage image = null;
if (value != null)
{
if (value.GetType() != typeof(StorageItemThumbnail))
{
throw new ArgumentException("Expected a StorageItemThumbnail as binding input.");
}
if (targetType != typeof(ImageSource))
{
throw new ArgumentException("Expected ImageSource as binding output.");
}
if (Windows.ApplicationModel.DesignMode.DesignModeEnabled)
{
image = new BitmapImage();
image.UriSource = new Uri("ms-appx:///Assets/DesignModeThumbnailPlaceholder.png");
}
else
{
StorageItemThumbnail ThumbNailFile = (StorageItemThumbnail)value;
if (ThumbNailFile == null)
return image;
image = new BitmapImage();
IRandomAccessStream thumbnailStream = ThumbNailFile as IRandomAccessStream;
image.SetSource(thumbnailStream);
}
}
return (image);
}
并且在我的XAML中绑定如下:
<DataTemplate x:Name="PictureGridTemplate2">
<Grid Height="150" Width="150">
<Grid.RowDefinitions>
<RowDefinition Height="*" />
<RowDefinition Height="Auto" />
</Grid.RowDefinitions>
<Border Grid.RowSpan="2" Background="Black" Opacity="0.8" />
<Image Width ="130" HorizontalAlignment="Center"
Stretch="Uniform" Source="{Binding ImageThumbNail, Converter={StaticResource ThumbnailFileToImageSourceConverter}}"/>
<TextBlock Grid.Row="1" MaxHeight="30" Text="{Binding Name}"
Foreground="White" TextTrimming="CharacterEllipsis"/>
</Grid>
</DataTemplate>
任何人都可以指出我在这方面出错的方向吗?
雪莉
* 已解决 *
我终于弄清楚是什么导致了这个问题。
这是 gridview 虚拟化、我的数据模型以及我如何通过转换器提供图像的副作用。
作为测试,我删除了转换器,更改了我的数据模型以存储缩略图的 BitmapImage 实例(比存储整个图像小)并直接绑定到那个 属性。这有效,当我在 gridview 中上下滚动时,图像显示在屏幕上。
然后我更改了我的数据模型,使 BitmapImage 属性 getter return 从 StorageItemThumbnail 属性 动态构建 BitmapImage - 与使用时相同的问题转换器。
通过在 getter 中添加一些调试语句,我看到第二次请求时 BitmapImage 的高度和宽度为 0。啊哈!那为什么是 0?
在第二个请求中查看 StorageItemThumbnail 属性 我看到 Stream 位置在 EOF(不像第一个请求中的 0)——所以这解释了 0 的宽度和高度,这解释了屏幕上的空图像控件。
我更改了我的代码以使用 StorageItemThumbnail.CloneStream,现在显示了所有图像。
下面是转换方法:
public object Convert(object value, Type targetType, object parameter, string language)
{
BitmapImage image = null;
if (value != null)
{
if (value.GetType() != typeof(StorageItemThumbnail))
{
throw new ArgumentException("Expected a StorageItemThumbnail as binding input.");
}
if (targetType != typeof(ImageSource))
{
throw new ArgumentException("Expected ImageSource as binding output.");
}
if ((StorageItemThumbnail)value == null)
{
System.Diagnostics.Debug.WriteLine("Thumbnail is null.");
return image;
}
image = new BitmapImage();
using (var thumbNailClonedStream = ((StorageItemThumbnail)value).CloneStream())
{
System.Diagnostics.Debug.WriteLine("Setting image source from cloned stream.");
image.SetSource(thumbNailClonedStream);
}
}
return (image);
}
感谢所有花时间回答并帮助我指明正确方向的人。
您可以尝试使用已编译的绑定 x:Bind 而不是 Binding
在这种情况下,您的应用程序性能会更快。
分阶段优化您的数据模板以逐步更新 GridView 项目:
<Grid Height="150" Width="150">
<Grid.RowDefinitions>
<RowDefinition Height="*" />
<RowDefinition Height="Auto" />
</Grid.RowDefinitions>
<Border Grid.RowSpan="2" Background="Black" Opacity="0.8" />
<Image Width ="130" HorizontalAlignment="Center"
Stretch="Uniform" Source="{Binding ImageThumbNail, Converter={StaticResource ThumbnailFileToImageSourceConverter}}" x:Phase="2"/>
<TextBlock Grid.Row="1" MaxHeight="30" Text="{Binding Name}" x:Phase="1"
Foreground="White" TextTrimming="CharacterEllipsis"/>
</Grid>
阅读此主题:
ListView and GridView UI optimization
ListView and GridView data virtualization