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