У меня есть ListView, который связан с экземплярами ItemsSource of Album. Поскольку может быть много (> 2000) экземпляров Album, я использую (горизонтально прокручивая) VirtualizingStackPanel в качестве ItemPanel:
<ListView.ItemsPanel>
<ItemsPanelTemplate>
<VirtualizingStackPanel Orientation="Horizontal" />
</ItemsPanelTemplate>
</ListView.ItemsPanel>
В качестве ItemTemplate я использую пользовательский UserControl, который привязан к альбомам в ItemsSource:
<DataTemplate x:Name="albumItem" x:DataType="local2:Album">
<local3:AlbumControl x:Name="albumControl" Album="{x:Bind}" />
</DataTemplate>
Альбом DependencyProperty на AlbumControl выполняет некоторые действия при возникновении новой привязки:
/// <summary>
/// Gets or sets the Album assigned to the control.
/// </summary>
public Album Album
{
get { return (Album)GetValue(AlbumProperty); }
set { SetValue(AlbumProperty, value); }
}
/// <summary>
/// Identifies the Album dependency property.
/// </summary>
public static readonly DependencyProperty AlbumProperty = DependencyProperty.Register(nameof(Album), typeof(Album), typeof(AlbumControl), new PropertyMetadata(null, HandleAlbumChange));
private static async void HandleAlbumChange(DependencyObject d, DependencyPropertyChangedEventArgs e)
{
if (d is AlbumControl control)
{
if (e.NewValue is Album album)
{
control.DoStuff(album);
await control.DoStuffAsync(album);
control.DoMoreStuff(album);
}
}
}
Поскольку ItemsPanel виртуализируется, во время прокрутки возможно, что новый альбом связывается с AlbumControl после DoStuff () и до завершения DoStuffAsyn c (). Это вызывает проблемы.
Я предполагаю, что мне нужно:
- какая-то блокировка (DoStuff () содержит блокировку, но вы не можете блокировать асинхронные вызовы c) или
- что-то вроде отмены обработки старого альбома и просто обработки нового альбома, или
- может быть, он не работает при ожидаемом вызове, или
- может быть, мои настройки полностью неверны.
Основной вопрос: как обрабатывать события привязки, которые происходят быстрее, чем обработка привязки?
==============================================
В ответ на комментарий я добавлю еще несколько деталей того, что я наблюдал.
control.DoStuff (album) очистил свойство ObservableCollection элемента AlbumControl. AlbumControl показывает эту коллекцию в ListView.
элемент управления await. DoStuffAsyn c (альбом) использовался для установки источника элемента управления изображением в AlbumControl. Альбом содержит информацию для этого источника в виде байта []. Мне нужно преобразовать это в RandomAccessStream, чтобы иметь возможность вызвать await bmp.SetSourceAsync(stream)
, а затем я могу использовать bmp (BitmapImage) в качестве источника. Байт [] не поддерживается файлом на диске, поэтому я не могу использовать Uri для установки источника элемента управления изображением.
После этого ожидаемого вызова я снова заполнил коллекцию ObservableCollection (control.DoMoreStuff ()). Если бы я сделал это таким образом, коллекция последнего AlbumControl содержала списочные элементы из нескольких альбомов. Указывает, что во время ожидаемого звонка был установлен новый альбом. Когда поток возвращается после окончания асинхронного c первого альбома, он повторно заполняет коллекцию, затем возвращается поток для второго альбома и также заполняет коллекцию. В результате списки элементов для обоих альбомов в коллекции. Я «решил» это, переместив Clear () после вызова метода asyn c, прямо перед этапом повторного заполнения. Но мне все еще было интересно, сделал ли я что-то сомнительное.
Я не смог найти способ предварительно вычислить BitmapImage, чтобы мне не понадобился вызов asyn c. Я продолжал получать сообщения «Marshalled for a Другой поток», означающие, что мне нужно было создать RandomAccessStream в потоке пользовательского интерфейса.
================================================= =============
Демонстрационный код доступен на https://antamista.visualstudio.com/_git/TestAlbumControl