来自ObservableCollection的ListView项,需要为实现做好准备

时间:2015-06-21 10:04:43

标签: c# wpf listview observablecollection ui-virtualization

我有一个ListView,它应该显示由“Name”,“Thumbnail”和“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();
      }

我这里有两个问题。

  1. ListView似乎实现了所有项目,而不仅仅是那些可见或在实现范围内的项目。我怀疑我的XAML以某种方式杀死虚拟化并尝试了许多解决方案但没有成功。请注意,我需要将ListView扩展到MainWindow的尺寸,而不是固定的高度和宽度。
  2. 我需要在项目即将实现时调用StartAnimation,并在离开视图时调用StopAnimation。
  3. 即使我的ListView没有正确虚拟化,如果我对ObservableCollections的工作方式的理解是正确的,它只是虚拟化管理的项目的UI表示,而不是项目本身,即从构造函数调用StartAnimation / StopAnimation /项目的析构函数没有多大帮助,因为无论如何它们在创建时都会为每个项目调用。

    是否有一种巧妙的方式以某种方式通知每个项目他们即将实现或离开ListView视图?

    更新 虚拟化无法正常工作的问题与 WrapPanel 有关,一旦我切换到 VirtualizingStackPanel ,它就开始正常工作。不幸的是,它与 WrapPanel 并不完全相同,并且由于.NET框架不提供 VirtualizingWrapPanel ,我选择使用here中的那个。它并不完美,但它能完成这项工作。

2 个答案:

答案 0 :(得分:0)

你说它是1/2

寻找对GetHashcode的调用 我认为它只是为了找到它而将其称为GetHashcode 偶然我发现它在项目虚拟化时被调用

让动画终止(不循环)

答案 1 :(得分:0)

我终于自己解决了这个问题。我知道它不会那么复杂,事实并非如此。由于我已经创建了自己的ListView继承类,名为MediaContainerListView,我可以覆盖它的一些虚拟方法。其中两个被证明是我想要的。

protected override void PrepareContainerForItemOverride( DependencyObject element, object item )

在项目即将出现之前调用,

protected override void ClearContainerForItemOverride( DependencyObject element, Object item )
在项目即将消失之前调用的

。所以我在第一个中调用StartAnimation,在第二个中调用StopAnimation,它可以完美地工作!