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 列表開啟虛擬化的方式


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM