zoukankan      html  css  js  c++  java
  • WPF 列表虚拟化时的滚动方式

    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只显示一半的情况。

    虚拟化 

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

    VirtualizingPanel其它属性有:

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

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

    VirtualizingPanel.VirtualizationMode="Recycling"

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

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

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

    开启虚拟化后,VirtualizingPanel.ScrollUnit会替换原有的ScrollViewer.CanContentScroll滚动方式

    虚拟化也有物理单元与逻辑单元之分,滚动单元设置会转移到VirtualizingPanel.ScrollUnit

    但是ScrollViewer.CanContentScroll="False"像素滚动,并不仅仅是滚动消耗性能。当数据很多时加载列表,即使开启了虚化化,因计算太耗性能,界面一样卡顿

    有一个解决办法,设置ScrollViewer.CanContentScroll="True"后,在虚拟化设置中,可以设置虚拟化滚动单元VirtualizingPanel.ScrollUnit="Pixel",此即为虚拟化时的像素滚动。

     另:虚拟化时的列表项滚动,VirtualizingPanel.ScrollUnit="Item"列表项

    注:

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

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

    因此当列表可见区域,Items数量或者高宽会变化时,列表滚动时会闪现。

    列表正确开启虚拟化方式,请看我的另一博客:WPF 列表开启虚拟化的方式

  • 相关阅读:
    [好文翻译]保卫你的日历
    如何使用PowerShell修改Host文件
    如何使用PowerShell修改注册表
    MSDN文章纠错Automating Microsoft SharePoint 2010 with Windows PowerShell 2.0 (book excerpt)
    如何在PowerShell中得到一个对象的所有属性名和方法名呢?
    Service Object Model
    记录一个问题的解决方法
    STSADM Sync 命令里的 – Ignoreisactive 标志位
    Javascript实现图片位置控制(鼠标拖拽 + 键盘方向键移动)源码分享
    从零开始学习jQuery (六) AJAX快餐【转】
  • 原文地址:https://www.cnblogs.com/kybs0/p/7649463.html
Copyright © 2011-2022 走看看