类别:.Net相关知识 / 日期:2013-12-21 / 浏览:2087 / 评论:0

1.  提出问题: 在进行Windows Store App开发的时候,很多的时候会遇到使用ListView绑定大量的数据进行展示,以前在Windows 8的时候,如果不进行处理,加载的时候不仅仅很慢而且UI显示也会被卡死。微软在Windows 8.1中对这样的情况进行了优化,在相同的情况下加载VisualTree的速度快很多,但是在数据未加载完的部分会出现一个默认的占位符,然后用读取出的数据去替代这些占位符。

在默认情况下,Windows 8.1会自动启用占位符,产生这样的效果,如果不需要,我们可以关闭占位符显示,只需要设置ListView的ShowsScrollingPlaceholders属性为False即可。当此属性设置为Flase后,ListView数据的加载就会像网页刷新一样一条一条的显示出来,可以看到滚动条会越来越窄,加载显示的数据会越来越多。但这也不是我们想要的效果,我们需要提升用户的体验效果,在加载的时候要为每一项的占位符显示一个进度条,来提示用户该项还有数据且未加载,这个时候就需要去实现ListView的ContainerContentChanging事件。 

 2.  前提知识 首先了解下ContainerContentChanging事件。该事件有两个参数一个是ListViewBase类型的sender还有一个是ContainerContentChangingEventArgs类型的args。前者主要是为 ListView 和 GridView 提供基础架构,后者主要是为事件提供参数的,接下来我们需要使用的就是它提供的参数。 ContainerContentChangingEventArgs类:

方法

RegisterUpdateCallback(TypedEventHandler(ListViewBase, ContainerContentChangingEventArgs))注册要在下一阶段再次调用的事件处理程序。
RegisterUpdateCallback(UInt32, TypedEventHandler(ListViewBase, ContainerContentChangingEventArgs))注册要在指定阶段再次调用的事件处理程序。

属性

Handled:bool获取或设置将路由事件标记为已处理的值。
InRecycleQueue:bool获取一个值,该值指示此容器是否位于 ListViewBase 的回收队列中,且未用于可视化数据项。
Item:object获取与此容器关联的数据项。
ItemContainer:SelectorItem获取用于显示当前数据项的 UI 容器。
ItemIndex:int获取与此容器关联的数据项的 ItemsSource 中的索引。
Phase:uint获取已调用此容器和数据项对的次数。

3.解决方法 前台XMAL界面:

<ListView ShowsScrollingPlaceholders="False" SelectionMode="None" IsItemClickEnabled="False" ItemsSource="{Binding NursingInterventionStandard}">
  <ListView.ItemTemplate>
    <DataTemplate>
      <Grid>
        <Grid.ColumnDefinitions>
          <ColumnDefinition Width="150" />
          <ColumnDefinition Width="1050" />
        </Grid.ColumnDefinitions>
        <ProgressRing Height="40" Grid.Column="0" Grid.ColumnSpan="2" Name="ImagePlaceholder" />
        <TextBlock Name="TxbItemName" Grid.Column="0" Text="{Binding NursingInterventionItem}" VerticalAlignment="Center" HorizontalAlignment="Center" />
        <ListView Name="ListTop" Grid.Column="1" ItemsSource="{Binding ItemDetails}" ShowsScrollingPlaceholders="False" SelectionMode="None" IsItemClickEnabled="False">
          <ListView.ItemTemplate>
            <DataTemplate>
              <Grid>
                <Grid.ColumnDefinitions>
                  <ColumnDefinition Width="140" />
                  <ColumnDefinition Width="90" />
                  <ColumnDefinition Width="800" />
                </Grid.ColumnDefinitions>
                <ProgressRing Height="40" Grid.Column="0" Grid.ColumnSpan="4" Name="ImagePlaceholder2" />
                <TextBlock Name="TxbDetailName" Grid.Column="0" Text="{Binding DetailItemName}" HorizontalAlignment="Center" VerticalAlignment="Center" />
                <TextBlock Name="TxbDetailScore" Grid.Column="1" Text="{Binding DetailItemScore}" HorizontalAlignment="Center" VerticalAlignment="Center" />
                <ListView Name="ListDetail" Grid.Column="2" SelectionMode="None" ShowsScrollingPlaceholders="False" ItemsSource="{Binding DeductionItems}" IsItemClickEnabled="False">
                  <ListView.ItemTemplate>
                    <DataTemplate>
                      <Grid>
                        <Grid.ColumnDefinitions>
                          <ColumnDefinition Width="520" />
                          <ColumnDefinition Width="100" />
                          <ColumnDefinition Width="120" />
                        </Grid.ColumnDefinitions>
                        <TextBlock Grid.Column="0" Text="{Binding DeductionItemName}" HorizontalAlignment="Center" VerticalAlignment="Center" />
                        <TextBlock Grid.Column="1" Text="{Binding DeductionItemScore}" HorizontalAlignment="Center" VerticalAlignment="Center" />
                        <TextBlock Grid.Column="2" Text="{Binding IsRightDeductionItem}" VerticalAlignment="Center" HorizontalAlignment="Center" />
                      </Grid>
                    </DataTemplate>
                  </ListView.ItemTemplate>
                </ListView>
              </Grid>
            </DataTemplate>
          </ListView.ItemTemplate>
        </ListView>
      </Grid>
    </DataTemplate>
  </ListView.ItemTemplate>
</ListView>

在上述的界面中,共有3个ListView,这样的多层嵌套的ListView在我们的开发中比较常见,尤其是在使用这样的表格去展示数据的时候。下面我们通过添加前两层ListView的ContainerContentChanging事件,来添加带进度条的占位符。 为第一个ListView添加ContainerContentChanging事件:

private void ListViewFirst_ContainerContentChanging(ListViewBase sender, ContainerContentChangingEventArgs args)
{
    var templateRooot = args.ItemContainer.ContentTemplateRoot as Grid;
    var projectItem = args.Item as InterventionItem;
    if (templateRooot == null || projectItem == null)
    {
        return;
    }
    var imgPlaceholder = templateRooot.FindName("ImagePlaceholder") as ProgressRing;
    var txtItemName = templateRooot.FindName("TxbItemName") as TextBlock;
    var listTop = templateRooot.FindName("ListTop") as ListView;
    if (imgPlaceholder == null || txtItemName == null || listTop == null)
    {
        return;
    }
    if (args.Phase == 0)
    {
        imgPlaceholder.IsActive = true; txtItemName.Opacity = 0;
        listTop.Opacity = 0; args.RegisterUpdateCallback(ListViewFirst_ContainerContentChanging);
    }
    else if (args.Phase == 1)
    {
        imgPlaceholder.IsActive = false;
        txtItemName.Text = projectItem.NursingInterventionItem; txtItemName.Opacity = 1;
        listTop.ItemsSource = projectItem.ItemDetails; listTop.Opacity = 1;
    }
    args.Handled = true;
}

为第二个ListView添加ContainerContentChanging事件:

private void ListViewScond_ContainerContentChanging(ListViewBase sender, ContainerContentChangingEventArgs args)
{
    var templateRooot = args.ItemContainer.ContentTemplateRoot as Grid;
    var projectItem = args.Item as InterventionItemDetail; if (templateRooot == null || projectItem == null)
    {
        return;
    }
    var imgPlaceholder = templateRooot.FindName("ImagePlaceholder2") as ProgressRing;
    var txbDetailName = templateRooot.FindName("TxbDetailName") as TextBlock;
    var txtDetailScore = templateRooot.FindName("TxbDetailScore") as TextBlock;
    var listDetail = templateRooot.FindName("ListDetail") as ListView;
    if (imgPlaceholder == null || txbDetailName == null || txtDetailScore == null || listDetail == null)
    {
        return;
    }
    if (args.Phase == 0)
    {
        imgPlaceholder.IsActive = true; txbDetailName.Opacity = 0;
        txtDetailScore.Opacity = 0; listDetail.Opacity = 0;
        args.RegisterUpdateCallback(ListViewScond_ContainerContentChanging);
    }
    else if (args.Phase == 1)
    {
        imgPlaceholder.IsActive = false;
        imgPlaceholder.IsActive = false;
        txtItemName.Text = projectItem.NursingInterventionItem;
        txtItemName.Opacity = 1;
        listTop.ItemsSource = projectItem.ItemDetails;
        listTop.ContainerContentChanging += ListView_ContainerContentChanging;
        listTop.Opacity = 1;
    }
    args.Handled = true;
}

4、代码注解

  • 要在ListView项中为Item添加一个进度条的元素,并且调整合适大小使其充满这一行。

  • 使用ItemContainer下ContentTemplateRoot获取当前ListView下的DataTemplate模板,用于找到我们要替换的元素。

  • 使用Item获取到要显示的数据项。

  • 当第一次调用事件的时候Phase为0,使用RegisterUpdateCallback方法可以再次调用该事件,并且Phase每调用一次就会加1。

  • 在事件第一次调用的时候只显示进度条,并且将其他元素都设置为隐藏。在第二次调用的时候将隐藏进度条并且显示这一项的真正内容。

  • 使用RegisterUpdateCallback方法的另一种重载可以指定Phase的值。

  • 前台代码只需要在第一个ListView注册ContainerContentChanging事件,在事件当Phase为1的时候为下一个ListView注册事件即可。

可能感兴趣的文章

评论区

发表评论 /

必填

选填

选填

◎欢迎讨论,请在这里发表您的看法及观点。