Приложение UWP с сеткой View Потеря изображений при прокрутке

Скорее, новичок в UWP и XAML, и я не уверен, как это отладить.

У меня есть приложение UWP, основанное на шаблоне Template10 Hamburger и образце инкрементальной загрузки Template10, а также несколько битов из образца просмотра фотографий ( Windows 8: создание простого средства просмотра фотографий в C# и XAML).

Я изменил главную страницу для отображения Gridview изображений из папки "Изображения" с постепенной загрузкой изображений. Я также вытащил некоторые из примера просмотра фотографий ( Windows 8: Создание простого просмотра фотографий в C# и 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 (меньше, чем хранилище всего изображения) и привязать его непосредственно к этому свойству. Это сработало, изображения отображались на экране, когда я прокручивал вверх и вниз по моему сетку.

Затем я изменил свою модель данных, чтобы метод получения свойства BitmapImage на лету возвращал сборку BitmapImage из свойства StorageItemThumbnail - та же проблема, что и при использовании конвертера.

Добавив несколько отладочных операторов в геттер, я увидел, что высота и ширина 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);

    }

Спасибо всем, кто нашел время, чтобы ответить и помочь направить меня в правильном направлении.

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 и GridView
Виртуализация данных ListView и GridView

Другие вопросы по тегам