Приложение 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