【问题标题】:UWP App with Grid View Losing Images when scrolling滚动时带有网格视图的 UWP 应用程序丢失图像
【发布时间】:2016-06-11 06:43:09
【问题描述】:

对 UWP 和 XAML 来说相当陌生,我不知道如何调试它。

我有一个基于 Template10 Hamburger 模板和 Template10 增量加载示例的 UWP 应用,以及来自示例照片查看器 (Windows 8: Making a Simple Photo Viewer in C# and XAML) 的一些内容。

我已经修改了主页以显示图片文件夹中图像的 Gridview,并以增量方式加载图像。我还从示例照片查看器 (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;}
}

为了显示这个,我使用一个转换器类来创建一个流来设置图像源:

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 属性获取器从 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);

    }

感谢所有花时间回答并帮助我指明正确方向的人。

【问题讨论】:

  • 转换器是原因。当您每次向上滚动创建图像时,它都会调用。而是存储 BitMapImage 本身。
  • 我不认为如果我在 Convert 方法中放置了一个断点,它只会在每个图像被增量加载时被命中一次。全部加载后,我可以随意上下滚动,并且不会触发断点。不存储 BitmapImage 的全部原因是为了保持低内存占用。
  • 谢谢你,雪莉。我和你有同样的问题,我已经厌倦了不断解构我的代码来学习这个平台(WPF 要简单得多!)。你的固定工作,所以非常感谢!

标签: win-universal-app template10


【解决方案1】:

您可以尝试使用编译绑定 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

【讨论】:

  • 现在我的问题不在于速度;图像,或者实际上是缩略图,加载速度相当快。稍后我将查看 x:Bind 并在资源字典日期模板中使用它。问题是图像控件停止显示它们。当应用程序第一次打开时,我的图像显示在屏幕上显示的 gridview 项目中,当我向下滚动时,我会看到所有其他图像。但是 - 如果我向上滚动,在某些时候图像不再显示,只有黑色 gridview 项目和名称作为文本框。
  • 这看起来像数据虚拟化问题
  • 是的,因为我能够通过在其列表视图模板中添加图像来重现我的应用程序在 Template10 增量示例代码中的不良行为。就像它不知道它已被视图卸载,所以它不知道何时重新加载它。我完全是新手,所以我不确定我错过了什么,但我正在查看您的建议和其他示例。
猜你喜欢
  • 1970-01-01
  • 2017-08-09
  • 1970-01-01
  • 1970-01-01
  • 2018-06-22
  • 1970-01-01
  • 1970-01-01
  • 2016-09-04
  • 1970-01-01
相关资源
最近更新 更多