C# UWP:使用DependencyProperty虚拟化StackPanel。处理前一个绑定之前的新绑定会导致问题
我有一个绑定到唱片集实例的ItemsSource的ListView。因为可以有许多(>2000)相册实例,所以我使用(水平滚动)VirtualzingStackPanel作为ItemPanel:C# UWP:使用DependencyProperty虚拟化StackPanel。处理前一个绑定之前的新绑定会导致问题,c#,uwp,C#,Uwp,我有一个绑定到唱片集实例的ItemsSource的ListView。因为可以有许多(>2000)相册实例,所以我使用(水平滚动)VirtualzingStackPanel作为ItemPanel: <ListView.ItemsPanel> <ItemsPanelTemplate> <VirtualizingStackPanel Orientation="Horizontal" /> </ItemsPanelTemplate
<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>
AlbumControl上的DependencyProperty相册在发生新绑定时执行一些操作:
/// <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);
}
}
}
//
///获取或设置分配给控件的相册。
///
公共相册
{
获取{return(Album)GetValue(AlbumProperty);}
set{SetValue(AlbumProperty,value);}
}
///
///标识相册依赖项属性。
///
public static readonly dependencProperty AlbumProperty=dependencProperty.Register(相册名称、相册类型、相册控制类型、新属性元数据(null、HandleAlbumChange));
私有静态异步void HandleAlbumChange(DependencyObject d、DependencyPropertyChangedEventArgs e)
{
如果(d是控制)
{
如果(例如,NewValue是相册)
{
对照组.DoStuff(相册);
等待控制。DoStuffAsync(相册);
控件.DoMoreStuff(相册);
}
}
}
因为ItemsPanel是虚拟化的,所以在滚动期间,有可能在DoStuff()之后和DoStuffAsync()完成之前将新相册绑定到AlbumControl。这会引起问题
我想我需要:
- 某种类型的锁定(DoStuff()包含一个锁,但不能锁定异步调用),或者
- 以某种方式取消处理旧相册而只处理新相册,或者
- 也许在等待的电话中出错了,或者
- 也许我的设置完全错了
wait bmp.SetSourceAsync(stream)
,然后我可以使用bmp(位图图像)作为源。字节[]没有磁盘上的文件支持,因此我无法使用Uri设置映像控件的源
在这个等待的调用之后,我重新填充了ObservableCollection(control.domorteuff())。如果我这样做,那么最后一个AlbumControl的集合包含来自多个相册的listitems。表示在等待的通话中设置了新唱片集。当线程在第一个相册的异步结束后返回时,它将重新填充集合,然后第二个相册的线程将返回,并重新填充集合。导致两个相册的列表项都在集合中。我通过在异步方法调用之后,即重新填充步骤之前移动Clear()来“解决”这个问题。但我仍然怀疑我是否做了一些可疑的事情
我找不到预计算BitmapImage的方法,因此不需要异步调用。我一直得到“为不同的线程编组”的错误,这意味着我需要在UI线程上创建RandomAccessStream
=========================================================
演示代码可以在上找到,我想我们可以从两个方面开始改变这一点:
Album
和Song
类继承INotifyPropertyChanged
接口,以便及时响应数据更改公共类相册:列表,INotifyPropertyChanged
{
// ...
私有字符串\u标题;
///
///专辑的标题
///
公共字符串标题
{
获取=>\u标题;
设置
{
_标题=价值;
OnPropertyChanged();
}
}
公共事件属性更改事件处理程序属性更改;
公共void OnPropertyChanged([CallerMemberName]字符串propertyName=”“)
{
PropertyChanged?.Invoke(这是新的PropertyChangedEventArgs(propertyName));
}
}
公共类歌曲:INotifyPropertyChanged
{
//...
私有字符串\u标题;
///
///歌名
///
公共字符串标题
{
获取=>\u标题;
设置
{
_标题=价值;
OnPropertyChanged();
}
}
公共事件属性更改事件处理程序属性更改;
公共void OnPropertyChanged([CallerMemberName]字符串propertyName=”“)
{
PropertyChanged?.Invoke(这是新的PropertyChangedEventArgs(propertyName));
}
}
private bool\u isLoading=false;
私有静态异步void HandleAlbumChange(DependencyObject d、DependencyPropertyChangedEventArgs e)
{
如果(d是控制)
{
if(控制装置.\u卸载)
回来
如果(例如,NewValue是相册)
{
控件。_isLoading=true;
//句柄代码
控件。_isLoading=false;
}
其他的
{
control.Songs.Clear();
control.albumSleeve.Source=null;
}
}
}
数据模板
谢谢。问题似乎是我使用了DependencyPropertyChangedEventArgs
e
的e.NewValue
中的相册:
if (e.NewValue is Album album)
{
control.DoStuff(album);
await control.DoStuffAsync(album);
control.DoMoreStuff(album);
}
如果我使用control.Album
,问题将不再显示。显然,当使用DependencyPropertyChangedEventArgs时
control.DoStuff(control.Album);
await control.DoStuffAsync(control.Album);
control.DoMoreStuff(control.Album);