標籤:c style class blog code java
11.2.2 VirtualizingStackPanel、ItemsStackPanel和ItemsWrapGrid虛擬化排列布局控制項
VirtualizingStackPanel、ItemsStackPanel和ItemsWrapGrid都是虛擬化布局控制項,一般情況下在介面的布局上很少會用到這些虛擬化排列的控制項,大部分都是封裝在列表的布局面板上使用,主要的目的就是為了實現列表上大資料量的虛擬化,從而極大地提高列表的效率。那麼其實這3個虛擬化布局控制項都是清單控制項的預設布局排列的方式,其中VirtualizingStackPanel控制項是ListBox的預設布局面板,ItemsStackPanel是ListView的預設布局面板,ItemsWrapGrid是GridView的預設布局面板。
VirtualizingStackPanel控制項和ItemsStackPanel控制項都是表示沿著水平方向或垂直垂直方向將內容虛擬化地排列在一行上。它們控制項所實現的排列布局效果和StackPanel控制項是一樣的,不同的是這些控制項可以實現虛擬化的邏輯。對於資料較多的列表布局,使用VirtualizingStackPanel控制項或者ItemsStackPanel控制項會比StackPanel控制項高效很多,因為虛擬化控制項只是把當前螢幕範圍內的資料顯示出來,其他的資料都通過虛擬化的技術進行處理,並沒有進行UI的初始化顯示,所以效率很高。ItemsWrapGrid控制項實現的則是網格的虛擬化布局效果,虛擬化原理也是和ItemsStackPanel控制項類似的,只不過他們排列的方式不一樣。
這些虛擬化排列布局控制項會計算可見項的數量,並處理來自 ItemsControl(如 ListBox)的ItemContainerGenerator,以便只為可見項建立 UI 元素。僅當StackPanel中包含的項控制項建立自己的項容器時,才會在該面板中發生虛擬化。 可以使用資料繫結來確保發生這一過程,如果是直接建立列表的項元素然後添加為虛擬化排列布局控制項的子物件,那麼這種方式是不會進行虛擬化處理的。下面以ItemsStackPanel來說明我們如何去利用虛擬化排列布局控制項去解決一些實際的問題。
ItemsStackPanel是ListView元素的預設項宿主。使用ListView清單控制項綁定資料的時候,預設是採用了ItemsStackPanel控制項對資料項目進行排列。如果你使用ItemsControl清單控制項來展示資料,要給這個列表增加虛擬化的功能,ItemsStackPanel對象元素必須包含在一個ItemsPanelTemplate中。現在我們再回過頭來看本章的第一個例子,用ItemsControl控制項綁定到2000個資料項目的集合的時候,載入的速度很慢,這就是沒有使用虛擬化的結果。如果在ItemsControl控制項上使用ItemsStackPanel來進行虛擬化布局,那麼你會發現載入的速度非常快。給ItemsControl控制項添加ItemsStackPanel虛擬化布局,需要把代碼修改成如下:
<ItemsControl x:Name="itemsControl"> <!--使用ItemsStackPanel控制項作為ItemsControl的布局面板--> < ItemsControl.ItemsPanel> <ItemsPanelTemplate> <ItemsStackPanel/> </ItemsPanelTemplate> </ ItemsControl.ItemsPanel> <ItemsControl.Template> <ControlTemplate TargetType="ItemsControl"> <ScrollViewer> <ItemsPresenter/> </ScrollViewer> </ControlTemplate> </ItemsControl.Template> <ItemsControl.ItemTemplate> <DataTemplate> ……省略若干代碼 </DataTemplate> </ItemsControl.ItemTemplate> </ItemsControl>
如果在列表中需要使用到ItemsStackPanel控制項虛擬化的技術的時候,還要注意一個事情是,不要破壞ScrollViewer和ItemsPresenter的結構,否則將實現不了虛擬化的效果。如果你在ScrollViewer和ItemsPresenter之間再添加一個StackPanel控制項,如下所示:
<ControlTemplate TargetType="ItemsControl"> <ScrollViewer> <StackPanel> <ItemsPresenter/> </StackPanel> </ScrollViewer> </ControlTemplate>
那麼這時候,ItemsStackPanel控制項會一次性把所有的資料都初始化,不會起到虛擬化的作用。因為ItemsStackPanel控制項虛擬化的時候是根據每個Item的固定的大小來進行布局的虛擬化處理的,當在ScrollViewer和ItemsPresenter中加入了其他的控制項之後會破壞了ItemsStackPanel控制項的虛擬化布局,導致ItemsStackPanel控制項無法準確地測量出來列表的資料項目的布局。
11.2.3 實現橫向虛擬化布局
通常我們實現的列表布局大部分都是豎向的布局,包括GridView控制項的布局整體上也是豎向的布局。那麼ListView控制項和ListBox控制項預設都是豎向垂直滾動的列表,如果要讓其水平滾動那麼就需要自訂其布局的面板,這時候我們就可以使用ItemsStackPanel控制項去實現了,如果我們並不需要ListView控制項的那麼多的功能和效果,就可以直接使用最基本的清單控制項ItemsControl控制項搭配ItemsStackPanel控制項去實現橫向滾動的效果,並且帶有虛擬化的功能。
下面我們用一個例子使用ItemsControl控制項橫向滾動展示圖片,在這個例子裡面會使用到ItemsStackPanel控制項的Horizontal布局。列表中會有100個資料項目,我們通過日誌來查看其載入的資料項目是怎樣的。
代碼清單11-7:橫向虛擬化列表(原始碼:第11章\Examples_11_7)
(1)首先,建立實體類和自訂的集合類,實體類Item和自訂的集合類ItemList。
Item.cs檔案主要代碼------------------------------------------------------------------------------------------------------------------ public class Item { // 圖片對象 public BitmapImage Image { get; set; } // 圖片名字 public string ImageName { get; set; } }
ItemList.cs檔案主要代碼------------------------------------------------------------------------------------------------------------------ public class ItemList : IList { // 設定集合的數量為100 public ItemList() { Count = 100; } // 集合數量屬性 public int Count { get; set; } // 根據索引返回資料項目 public object this[int index] { get { // 載入的圖片是程式裡面的圖片資源,5張圖片迴圈載入 int imageIndex = 5 - index % 5; Debug.WriteLine("載入的集合索引是:" + index ); return new Item { ImageName = "圖片" + index, Image = new BitmapImage(new Uri("ms-appx:///Images/" + imageIndex + ".jpg", UriKind.RelativeOrAbsolute)) }; } set { throw new NotImplementedException(); } } //……省略若干代碼 }
(2)實現ItemsControl的橫向虛擬化布局。
要實現ItemsControl的橫向虛擬化布局,除了使用ItemsStackPanel控制項的Horizontal布局,還需要在ItemsControl中設定ScrollViewer.HorizontalScrollBarVisibility="Auto",這樣列表就可以水平滾動了。列表的代碼如下:
MainPage.xaml檔案主要代碼------------------------------------------------------------------------------------------------------------------ <ItemsControl x:Name="list"> <!--使用ItemsStackPanel控制項作為ItemsControl的布局面板--> <ItemsControl.ItemsPanel> <ItemsPanelTemplate> <ItemsStackPanel Orientation="Horizontal"/> </ItemsPanelTemplate> </ItemsControl.ItemsPanel> <ItemsControl.Template> <ControlTemplate TargetType="ItemsControl"> <ScrollViewer ScrollViewer.HorizontalScrollBarVisibility="Auto" ScrollViewer.VerticalScrollBarVisibility ="Disabled"> <ItemsPresenter/> </ScrollViewer> </ControlTemplate> </ItemsControl.Template> <ItemsControl.ItemTemplate> <DataTemplate> <StackPanel> <Image Source="{Binding Image}" Width="144" Height="240" Stretch="UniformToFill"></Image> <TextBlock Text="{Binding ImageName}"></TextBlock> </StackPanel> </DataTemplate> </ItemsControl.ItemTemplate> </ItemsControl>
MainPage.xaml.cs檔案主要代碼------------------------------------------------------------------------------------------------------------------ public MainPage() { InitializeComponent(); list.ItemsSource = new ItemList(); }
(3)列表的運行效果11.8所示,採用Debug調試下運行程式可以看到日誌顯示列表只是初始化了10個資料項目,日誌如下所示:
/*日誌開始*/
載入的集合索引是:0
載入的集合索引是:1
載入的集合索引是:2
載入的集合索引是:3
載入的集合索引是:4
載入的集合索引是:5
載入的集合索引是:6
載入的集合索引是:7
載入的集合索引是:8
載入的集合索引是:9
/*日誌開始*/
原始碼下載:http://vdisk.weibo.com/s/zt_pyrfNHoezI