WPF 列表虚拟化时的滚动方式
ListBox的滾動(dòng)方式 分為像素滾動(dòng)和列表項(xiàng)滾動(dòng)
通過ListBox的附加屬性ScrollViewer.CanContentScroll來設(shè)置。因此ListBox的默認(rèn)模板中,含有ScrollViewer,ScrollViewer下存放列表內(nèi)容
<ScrollViewer FocusVisualStyle="{x:Null}"><ItemsPresenter SnapsToDevicePixels="{TemplateBinding UIElement.SnapsToDevicePixels}"/></ScrollViewer>?而CanContentScroll,true支持邏輯單元(Item),false支持物理單元(像素)。源碼如下:
/// <summary>/// 獲取或設(shè)置一個(gè)值,該值指示是否支持元素 <see cref="T:System.Windows.Controls.Primitives.IScrollInfo" /> 接口允許滾動(dòng)。/// </summary>/// <returns>/// <see langword="true" /> 如果 <see cref="T:System.Windows.Controls.ScrollViewer" /> 執(zhí)行滾動(dòng)操作使得在邏輯單元; 方面 <see langword="false" /> 如果 <see cref="T:System.Windows.Controls.ScrollViewer" /> 執(zhí)行滾動(dòng)操作使得在物理單元方面。/// 默認(rèn)值為 <see langword="false" />。/// </returns>public bool CanContentScroll{get{return (bool) this.GetValue(ScrollViewer.CanContentScrollProperty);}set{this.SetValue(ScrollViewer.CanContentScrollProperty, value);}}滾動(dòng)
1、像素滾動(dòng)(物理單元) ScrollViewer.CanContentScroll=false
通過查看源碼,我們可以得知CanContentScroll的默認(rèn)值為false。所以列表ListBox/ListView/DataGrid默認(rèn)像素滾動(dòng)
/// <summary>/// 標(biāo)識(shí) <see cref="P:System.Windows.Controls.ScrollViewer.CanContentScroll" /> 依賴屬性。/// </summary>/// <returns>/// <see cref="P:System.Windows.Controls.ScrollViewer.CanContentScroll" /> 依賴項(xiàng)屬性的標(biāo)識(shí)符。/// </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;}}像素滾動(dòng)的優(yōu)點(diǎn):平滑--因?yàn)榘凑障袼貪L動(dòng),肉眼分辨較低。
像素滾動(dòng)的缺點(diǎn):耗性能-列表中每個(gè)項(xiàng),都要計(jì)算出寬高具體數(shù)值,且滾動(dòng)時(shí)時(shí)計(jì)算。如果列表中數(shù)量過多,就相當(dāng)卡了。
2、列表項(xiàng)滾動(dòng)(邏輯單元) ScrollViewer.CanContentScroll="True"
按照Item高寬為滾動(dòng)單位。
列表項(xiàng)滾動(dòng)時(shí),列表只會(huì)滾動(dòng)到一個(gè)完整的Item,不會(huì)有一個(gè)Item只顯示一半的情況。
?
虛擬化?
通過VirtualizingPanel,設(shè)置列表ListBox/ListView/DataGrid是否開啟虛擬化
VirtualizingPanel其它屬性有:
?VirtualizingPanel.ScrollUnit="Pixel"--虛擬化滾動(dòng)單位(像素/單元)
VirtualizingPanel.IsVirtualizing="True" --是否虛擬
VirtualizingPanel.VirtualizationMode="Recycling"
?VirtualizingPanel.CacheLengthUnit="Item" --緩存單位
VirtualizingPanel.CacheLength="20,20"-上下緩存數(shù)量
?
開啟虛擬化:為何需要設(shè)置ScrollViewer.CanContentScroll="True"?
開啟虛擬化后,VirtualizingPanel.ScrollUnit會(huì)替換原有的ScrollViewer.CanContentScroll滾動(dòng)方式
虛擬化也有物理單元與邏輯單元之分,滾動(dòng)單元設(shè)置會(huì)轉(zhuǎn)移到VirtualizingPanel.ScrollUnit
但是ScrollViewer.CanContentScroll="False"像素滾動(dòng),并不僅僅是滾動(dòng)消耗性能。當(dāng)數(shù)據(jù)很多時(shí)加載列表,即使開啟了虛化化,因計(jì)算太耗性能,界面一樣卡頓。
有一個(gè)解決辦法,設(shè)置ScrollViewer.CanContentScroll="True"后,在虛擬化設(shè)置中,可以設(shè)置虛擬化滾動(dòng)單元VirtualizingPanel.ScrollUnit="Pixel",此即為虛擬化時(shí)的像素滾動(dòng)。
?另:虛擬化時(shí)的列表項(xiàng)滾動(dòng),VirtualizingPanel.ScrollUnit="Item"列表項(xiàng)
?
注:
VirtualizingPanel.ScrollUnit和ScrollViewer.CanContentScroll的設(shè)置滾動(dòng)單元一樣。
設(shè)置虛擬單位為邏輯單元時(shí),滾動(dòng)時(shí)會(huì)自動(dòng)滾動(dòng)到一個(gè)完整的項(xiàng),而不是滾動(dòng)到項(xiàng)的部分。
因此當(dāng)列表可見區(qū)域,Items數(shù)量或者高寬會(huì)變化時(shí),列表滾動(dòng)時(shí)會(huì)閃現(xiàn)。
?
列表正確開啟虛擬化方式,請(qǐng)看我的另一博客:WPF 列表開啟虛擬化的方式
轉(zhuǎn)載于:https://www.cnblogs.com/kybs0/p/7649463.html
總結(jié)
以上是生活随笔為你收集整理的WPF 列表虚拟化时的滚动方式的全部內(nèi)容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: opencv:图像的基本变换
- 下一篇: C#下的两种加密方式MD5和DEC