码迷,mamicode.com
首页 > Windows程序 > 详细

WPF ListBox/ListView/DataGrid 列表滚动与虚拟化

时间:2018-04-08 22:25:35      阅读:1478      评论:0      收藏:0      [点我收藏+]

标签:attach   mod   宽高   ram   OLE   .com   像素   nbsp   alt   

ListBox的滚动方式 分为像素滚动和单元滚动

通过ListBox的附加属性ScrollViewer.CanContentScroll来设置。因此ListBox的默认模板中,含有ScrollViewer,ScrollViewer下存放列表内容

    <ScrollViewer FocusVisualStyle="{x:Null}">
        <ItemsPresenter SnapsToDevicePixels="{TemplateBinding UIElement.SnapsToDevicePixels}"/>
    </ScrollViewer>

 而CanContentScroll,true支持逻辑单元(Item),false支持物理单元(像素)。源码如下:

    /// <summary>
    ///   获取或设置一个值,该值指示是否支持元素 <see cref="T:System.Windows.Controls.Primitives.IScrollInfo" /> 接口允许滚动。
    /// </summary>
    /// <returns>
    ///   <see langword="true" /> 如果 <see cref="T:System.Windows.Controls.ScrollViewer" /> 执行滚动操作使得在逻辑单元; 方面 <see langword="false" /> 如果 <see cref="T:System.Windows.Controls.ScrollViewer" /> 执行滚动操作使得在物理单元方面。
    ///    默认值为 <see langword="false" />/// </returns>
    public bool CanContentScroll
    {
      get
      {
        return (bool) this.GetValue(ScrollViewer.CanContentScrollProperty);
      }
      set
      {
        this.SetValue(ScrollViewer.CanContentScrollProperty, value);
      }
    }

滚动

1、像素滚动(物理单元) ScrollViewer.CanContentScroll=false

通过查看源码,我们可以得知CanContentScroll的默认值为false。所以列表ListBox/ListView/DataGrid默认像素滚动

    /// <summary>
    ///   标识 <see cref="P:System.Windows.Controls.ScrollViewer.CanContentScroll" /> 依赖属性。
    /// </summary>
    /// <returns>
    ///   <see cref="P:System.Windows.Controls.ScrollViewer.CanContentScroll" /> 依赖项属性的标识符。
    /// </returns>
    [CommonDependencyProperty]
    public static readonly DependencyProperty CanContentScrollProperty = DependencyProperty.RegisterAttached(nameof (CanContentScroll), typeof (bool), typeof (ScrollViewer), (PropertyMetadata) new FrameworkPropertyMetadata(BooleanBoxes.FalseBox));
  [FriendAccessAllowed]
  internal static class BooleanBoxes
  {
    internal static object TrueBox = (object) true;
    internal static object FalseBox = (object) false;

    internal static object Box(bool value)
    {
      if (value)
        return BooleanBoxes.TrueBox;
      return BooleanBoxes.FalseBox;
    }
  }

像素滚动的优点:平滑--因为按照像素滚动,肉眼分辨较低。

像素滚动的缺点:耗性能-列表中每个项,都要计算出宽高具体数值,且滚动时时计算。如果列表中数量过多,就相当卡了。

2、列表项滚动(逻辑单元) ScrollViewer.CanContentScroll="True"

按照Item高宽为滚动单元。

单元滚动时,列表只会滚动到一个完整的Item,不会有一个Item只显示一半的情况。

--基于上面的情况,当列表刚好有一个ItemA只显示部分时,因业务需要,设置滚动到ItemA,整个列表会移动位置使ItemA完整显示。

 

虚化化 

通过VirtualizingPanel,设置列表ListBox/ListView/DataGrid是否开启虚拟化

VirtualizingPanel其它属性有:

 VirtualizingPanel.ScrollUnit="Pixel"--虚拟化滚动单位(像素/单元)

VirtualizingPanel.IsVirtualizing="True" --是否虚拟

VirtualizingPanel.VirtualizationMode="Recycling"

 VirtualizingPanel.CacheLengthUnit="Item" --缓存单位

VirtualizingPanel.CacheLength="20,20"-上下缓存数量

 

开启虚拟化:为何需要设置ScrollViewer.CanContentScroll="True"?

因为ScrollViewer.CanContentScroll="False"为物理单元,即像素滚动,当数据很多时,即使开启了虚化化,因计算太耗性能,界面一样卡顿。
因此设置ScrollViewer.CanContentScroll="True"

 

设置虚拟化

设置VirtualizingPanel.IsVirtualizing="True" 开启虚拟化

VirtualizingPanel.ScrollUnit="Pixel"像素,VirtualizingPanel.ScrollUnit="Item"列表项

注意到没,虚拟化也有物理单元与逻辑单元之分。因此设置ScrollViewer.CanContentScroll="True"之后,滚动单元设置就转移到VirtualizingPanel.ScrollUnit了

 

注:

VirtualizingPanel.ScrollUnit和ScrollViewer.CanContentScroll的设置滚动单元一样。

当列表中显示的项总高不等于列表显示高度,即:ItemHeight*n !=ListBox.Height,最好使用VirtualizingPanel.ScrollUnit="Item"。

设置虚拟单位为单元项,滚动时会自动滚动到一个完整的项,而不是滚动到项的部分。

VirtualizingPanel.ScrollUnit="Pixel",会显示如右图:技术分享图片

 

案例:虚拟化时像素滚动和列表项滚动

ScrollViewer.CanContentScroll="True"
VirtualizingPanel.IsVirtualizing="True"
VirtualizingPanel.ScrollUnit="Pixel"
ScrollViewer.CanContentScroll="True"
VirtualizingPanel.IsVirtualizing="True"
VirtualizingPanel.ScrollUnit="Item"

 

WPF ListBox/ListView/DataGrid 列表滚动与虚拟化

标签:attach   mod   宽高   ram   OLE   .com   像素   nbsp   alt   

原文地址:https://www.cnblogs.com/kybs0/p/7649463.html

(0)
(0)
   
举报
评论 一句话评论(0
登录后才能评论!
© 2014 mamicode.com 版权所有  联系我们:gaon5@hotmail.com
迷上了代码!