我有一个 ListView,它应该显示由“名称”、“缩略图”和“AnimationPosition”属性组成的相当多的项目。每个项目类型中的后台任务负责切换缩略图以对其进行动画处理。
现在不言而喻,这是一个相当繁重的操作,应该限制为尽可能少的项目,例如虚拟化 ListView 的可见/实现项目。现在我已经将 ListView 的 DataContext 设置为 ObeservableCollection 实例,并将其绑定到其类型的属性。这是我的 XAML 代码的一瞥。
<TabControl Grid.Row="0" Grid.Column="2">
<TabControl.Resources>
<Style x:Key="MediaItemStyle" TargetType="{x:Type ListViewItem}">
<Setter Property="Margin" Value="5,5,5,5"/>
<Setter Property="Padding" Value="0,0,0,0"/>
<Setter Property="HorizontalAlignment" Value="Left"/>
<Setter Property="Template">
<Setter.Value>
<ControlTemplate TargetType="{x:Type ListViewItem}">
<Grid HorizontalAlignment="Left" VerticalAlignment="Top" Height="Auto" >
<Border x:Name="border" BorderBrush="{x:Null}" BorderThickness="1" HorizontalAlignment="Stretch" VerticalAlignment="Stretch" CornerRadius="2.5"/>
<StackPanel HorizontalAlignment="Stretch" VerticalAlignment="Stretch">
<ContentPresenter/>
</StackPanel>
</Grid>
</ControlTemplate>
</Setter.Value>
</Setter>
</Style>
<Style TargetType="custom:MediaContainerListView">
<Setter Property="ItemsSource" Value="{Binding}"/>
<Setter Property="ScrollViewer.HorizontalScrollBarVisibility" Value="Disabled"/>
<Setter Property="ItemContainerStyle" Value="{StaticResource MediaItemStyle}"/>
<Setter Property="ItemsPanel">
<Setter.Value>
<ItemsPanelTemplate>
<WrapPanel/>
</ItemsPanelTemplate>
</Setter.Value>
</Setter>
<Setter Property="ItemTemplate">
<Setter.Value>
<DataTemplate>
<DockPanel Width="256">
<Image DockPanel.Dock="Top" Height="144" StretchDirection="Both"
Stretch="Fill" Source="{Binding Thumbnail.Source,Mode=OneWay}"/>
<ProgressBar DockPanel.Dock="Top" Height="2"
Minimum="0" Maximum="{Binding Thumbnail.AnimationPosition.Length}"
Value="{Binding Thumbnail.AnimationPosition.Position}"
Visibility="{Binding Thumbnail.AnimationPosition.Visibility}"/>
<TextBlock DockPanel.Dock="Bottom" Height="40"
TextWrapping="Wrap" TextTrimming="CharacterEllipsis"
TextAlignment="Center" Text="{Binding Name}"/>
</DockPanel>
</DataTemplate>
</Setter.Value>
</Setter>
</Style>
</TabControl.Resources>
<TabItem Header="">
<custom:MediaContainerListView x:Name="MediaContainerView"></custom:MediaContainerListView>
</TabItem>
</TabControl>
基本上,我有两种方法可以为每个单独的项目启动/停止动画。
public async void StartAnimation()
{
if( Count > 1 )
{
Task thumbnailAnimationTask = AnimationTask( AnimationCancellationToken.Token );
await thumbnailAnimationTask;
}
}
public void StopAnimation()
{
AnimationCancellationToken.Cancel();
}
我这里有两个问题。
- ListView 似乎实现了所有项目,而不仅仅是那些可见或在实现范围内的项目。我怀疑我的 XAML 以某种方式杀死了虚拟化,并且尝试了许多解决方案但没有成功。请注意,我需要我的 ListView 可以扩展到 MainWindow 的尺寸,而不是固定的高度和宽度。
- 当一个项目即将被实现时,我需要调用 StartAnimation,当它离开视图时,我需要调用 StopAnimation。
即使我的 ListView 没有正确虚拟化,如果我对 ObservableCollections 工作原理的理解是正确的,那么它只是由虚拟化管理的项目的 UI 表示,而不是项目本身,即从 Constructor/Destructor 调用 StartAnimation/StopAnimation这些项目并没有多大帮助,因为无论如何在创建时它们都被要求用于每个项目。
是否有一种巧妙的方法可以以某种方式通知每个项目它们即将实现或离开 ListView 视图?
更新: 虚拟化无法正常工作的问题与WrapPanel有关,一旦我切换到VirtualizingStackPanel,它就开始正常工作。不幸的是,它与WrapPanel并不完全相同,并且由于 .NET 框架不提供VirtualizingWrapPanel,因此我选择使用此处的那个。它并不完美,但可以完成工作。