ListBox的滾動方式 分爲像素滾動和列表項滾動html
經過ListBox的附加屬性ScrollViewer.CanContentScroll來設置。所以ListBox的默認模板中,含有ScrollViewer,ScrollViewer下存放列表內容緩存
<ScrollViewer FocusVisualStyle="{x:Null}"> <ItemsPresenter SnapsToDevicePixels="{TemplateBinding UIElement.SnapsToDevicePixels}"/> </ScrollViewer>
而CanContentScroll,true支持邏輯單元(Item),false支持物理單元(像素)。源碼以下:post
/// <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); } }
一、像素滾動(物理單元) ScrollViewer.CanContentScroll=false性能
經過查看源碼,咱們能夠得知CanContentScroll的默認值爲false。因此列表ListBox/ListView/DataGrid默認像素滾動this
/// <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; } }
像素滾動的優勢:平滑--由於按照像素滾動,肉眼分辨較低。url
像素滾動的缺點:耗性能-列表中每一個項,都要計算出寬高具體數值,且滾動時時計算。若是列表中數量過多,就至關卡了。spa
二、列表項滾動(邏輯單元) ScrollViewer.CanContentScroll="True"code
按照Item高寬爲滾動單位。htm
列表項滾動時,列表只會滾動到一個完整的Item,不會有一個Item只顯示一半的狀況。blog
經過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 列表開啓虛擬化的方式