天天看點

WPF 清單虛拟化時的滾動方式

原文: 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 清單開啟虛拟化的方式

繼續閱讀