Topic: WPF – Virtualization – VirutalizationStackPanel and ItemsPanelTemplate
标题: WPF – 控件虚拟化- 简单介绍VirutalizationStackPanel和ItemsPanelTemplate
在ItemsPanel上的虚拟化, 你可以使用VirutalizationStackPanel, 和 “ItemsPanelTemplate”, 以下是一个虚拟化的例子.
Virtualization on the ItemsPanel, you can use the VirutalizationStackPanel, together with the “ItemsPanelTemplate”, here is a live use example of that .
<cn:CustomListView.ItemsPanel> <ItemsPanelTemplate> <VirtualizingStackPanel cmbh:PixelBasedScrollingBehavior.IsEnabled="True" VirtualizationMode="Recycling"/> </ItemsPanelTemplate> </cn:CustomListView.ItemsPanel>
我们将关注两点,一点是VirtualizingStackPanel,另一点是ItemsPanelTemplate
So we will focus on two parts, one is the VirtualizingStackPanel and the other is ItemsPanelTemplate
VirtualizingStackPanel
一般的来说,标准的布局系统为每一个元素创建元素容器和布局元素,虚拟化这个词的意思是指一种从大量的数据中,只显示用户界面可见一部分元素的技巧。如果只有少量的元素被显示,但生成许多UI元素的做法会影响到他的performance. VirtualizingStackPanel计算,控制ItemsControl (比如说ListBox 或ListView)的ItemContainerGenerator生成可视部分元素。
So generally, the standard layout system create item containers and layout for each item associate with a list control, the word “virtualize” refers to a technique by which a subset of user interface (UI) elements are generated from a larger number of data items based on which items are visible on-screen. Generating many UI elements when only a few elements might be on the screen can adversely affect the performance of your application. The VirtualizingStackPanel calculates the number of visible items and works with the ItemContainerGenerator from an ItemsControl (such as ListBox or ListView) to create UI elements only for Visible items.
虚拟化只是在panel里面的items control生成自己的item container.可以采用数据绑定的办法确保如此。如果item container是被显示的创立的话,那么virtualizingStackPanel比没用virtualizingStackPanel没有效率的优势。
Virtualization in a StackPanel only occurs when the items control contained in the panel creates its own item container. You can ensure this happen by using DataBinding . In Scenarios where item container are created and added to the items control. A virtualizingStackPanel offers no performance advantage over a StackPanel.
VirtualizingStackPanel是ListBox元素的默认元素容器,默认的,IsVirtualizing属性值是true.
VirtualizingStackPanel is the default items host for ListBox element, by default, the IsVirtualizing property is set to true.
IsVirtualizing属性值是false时,和不用VirtualizingStackPanel效果是一样的。
When isVirtualizing is set to false, a VirtualizingStackPanel behaves the same as an ordinary StackPanel.
如下所例,用IsVirtualizing这个attached属性,我们可以控制ListBox的虚拟化。
So an example of such, with the attached property, IsVirtualizing, you can Virtualizing on ListBox as such ..
<Page x:Class="DemoVirtualizingStackPanel.ListboxVirutalizationPage" xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation" xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml" Title="ListboxVirutalizationPage" VerticalAlignment="Top" > <Page.Resources> <XmlDataProvider x:Key="Leagues" Source="Leagues.xml" XPath="Leagues/League" /> <DataTemplate x:Key="NameDataStyle" > <TextBlock Text="{Binding XPath=@name}" FontFamily="Arial" FontSize="8" Foreground="Black" > </TextBlock> </DataTemplate> </Page.Resources> <Border HorizontalAlignment="Left" VerticalAlignment="Top" BorderBrush="Black" BorderThickness="2"> <StackPanel DataContext="{StaticResource Leagues}" > <TextBlock Text="{Binding XPath=@name}" FontFamily="Arial" FontSize="18" Foreground="Black" ></TextBlock> <ListBox VirtualizingStackPanel.IsVirtualizing="True" ItemsSource="{Binding XPath=Team}" ItemTemplate="{DynamicResource NameDataStyle}" ></ListBox> </StackPanel> </Border> </Page>
可以进一步的控制VirtualizationMode,值Recycling和Standard。
You can further control the VirtualizationMode, possible value are Recycling and Standard.
<Page x:Class="DemoVirtualizingStackPanel.RecyclingVirtualizationPage" xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation" xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml" xmlns:src="clr-namespace:DemoVirtualizingStackPanel.ViewModels" Title="RecyclingVirtualizationPage"> <StackPanel> <StackPanel.Resources> <src:LotsOfItems x:Key="data" /> </StackPanel.Resources> <ListBox Height="150" ItemsSource="{StaticResource data}" VirtualizingStackPanel.VirtualizationMode="Recycling" ></ListBox> </StackPanel> </Page>
如果你感兴趣的话,ViewModel定义如下:
For your interest, the ViewModel is like this:
public class LotsOfItems : ObservableCollection<string> { public LotsOfItems() { for (int i = 0; i < 1000; i++) this.Add("Item " + i.ToString()); } }
Xml provider的数据xml如下:
And the Xml that provides the data is like this:
// Leagues.xml <?xml version="1.0" encoding="utf-8" ?> <Leagues> <League name="England League"> <Team name="Liz" /> <Team name="Liverpool" /> <Team name="Manchester Union" /> <Team name="Charls" /> <Team name="Arsenal" /> <Team name="Mancester City" /> <Team name="New Castle" /> <Team name="Cambridge U" /> <Team name="Oxford U" /> <Team name="East London" /> </League> </Leagues>
ItemsPanelTemplate
在我们看到的第一个例子中,要介绍的第二个元素是“ItemsPanelTemplate”.
And in the first example that we introduced, the second items that we may use is the “ItemsPanelTemplate”.
ItemsPanelTemplate定义了作为布局元素的panel,GroupStyle有一个panel属性,他的类型是ItemsPanelTemplate,ItemsControl类型有一个ItemsPanel属性,值是ItemsPanelTemplate.每一个ItemsControl有一个默认的ItemsPanel类型,ItemsControl的ItemsPanel是StackPanel, ListBoxItemsPanel是VirtualizingStackPanel,MenuItem的值是WrapPanel,Status的为DockPanel.
The ItemsPanelTemplate specifies the panel that is used for the layout of items. GroupStyle has a Panel property that is of type ItemsPanelTemplate.ItemsControl types have an ItemsPanel property that is of type ItemsPanelTemplate.
Each ItemsControl type has a default ItemsPanelTemplate. For the ItemsControl class, the default ItemsPanel value is an ItemsPanelTemplate that specifies aStackPanel. For the ListBox, the default uses the VirtualizingStackPanel. For MenuItem, the default uses WrapPanel. For StatusBar, the default usesDockPanel.
下面的例子中,我们将要介绍几种创建vertical ListBox的方法。
In the following examples. We will introduce ways to create Vertical ListBox.
例子1 – ItemsPanel 属性
Example 1 – With the ItemsPanel property
<Style TargetType="ListBox" > <Setter Property="ItemsPanel"> <Setter.Value> <ItemsPanelTemplate> <StackPanel Orientation="Horizontal" VerticalAlignment="Center" HorizontalAlignment="Center"></StackPanel> </ItemsPanelTemplate> </Setter.Value> </Setter> </Style>
装配起来,我们定义了“DataTemplate” and the “XmlDataProvider”,整体的代码如下:
To wire it up, we defined the “DataTemplate” and the “XmlDataProvider”. The overall code is as follow.
<Page x:Class="DemoItemsPanelTemplate.HorizontalListBoxPage" xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation" xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml" Title="HorizontalListBoxPage"> <Page.Resources> <XmlDataProvider x:Key="Leagues" Source="Leagues.xml" XPath="Leagues/League" /> <DataTemplate x:Key="NameDataStyle" > <TextBlock Text="{Binding XPath=@name}" FontFamily="Arial" FontSize="8" Foreground="Black" > </TextBlock> </DataTemplate> <Style TargetType="ListBox" > <Setter Property="ItemsPanel"> <Setter.Value> <ItemsPanelTemplate> <StackPanel Orientation="Horizontal" VerticalAlignment="Center" HorizontalAlignment="Center"></StackPanel> </ItemsPanelTemplate> </Setter.Value> </Setter> </Style> </Page.Resources> <Grid> <!-- style is the default Style specified in the Page.Resources --> <ListBox DataContext="{StaticResource Leagues}" ItemsSource="{Binding XPath=Team}" ItemTemplate="{DynamicResource NameDataStyle}" ></ListBox> </Grid> </Page>
在后面的例子中,我们将复用ListBox, XmlDataProvider 和DataTemplate定义。
We will reuse the ListBox, XmlDataProvider and DataTemplate definition in following examples.
例子2
Example 2
除了使用ItemsPanelTemplate,在下面的例子中,我们再ControlTemplate里定义了一个horizontal stackpanel,请注意,我们使用了IsItemsHost属性,表示生成的元素将到这个StackPanel里面去。
Instead of using the ItemsPanelTemplate, in this example, we specify a horizontal stackpanel within the ControlTemplate, note that we uses IsItemsHost property of the StackPanel, indicating that the generated items should go in the panel..
这个方法的不足是,我们不替换ControlTemplate就不能替换ItemsPanelTemplate。Style的定义如下
The drawback is user cannot replace the ItemsPanelTemplate without using a ControlTemplate. So using this technique with care.
Style definition is as follow.
<Style TargetType="ListBox"> <Setter Property="Template"> <Setter.Value> <ControlTemplate TargetType="ListBox"> <Border CornerRadius="5" Background="{TemplateBinding ListBox.Background}"> <ScrollViewer HorizontalScrollBarVisibility="Auto"> <StackPanel Orientation="Horizontal" VerticalAlignment="Center" HorizontalAlignment="Center" IsItemsHost="True" > </StackPanel> </ScrollViewer> </Border> </ControlTemplate> </Setter.Value> </Setter> </Style>
例子3
Example 3:
我们可以同时替换ItemsPanel和Control Template,代码如下:
We can alternatively replace both the ItemsPanel and the Control Template, code as follow.
<Style TargetType="{x:Type ListBox}"> <Setter Property="ItemsPanel"> <Setter.Value> <ItemsPanelTemplate> <StackPanel Orientation="Horizontal" VerticalAlignment="Center" HorizontalAlignment="Center"></StackPanel> </ItemsPanelTemplate> </Setter.Value> </Setter> <Setter Property="Template"> <Setter.Value> <ControlTemplate TargetType="{x:Type ListBox}" > <Border CornerRadius="5" Background="{TemplateBinding ListBox.Background}"> <ScrollViewer HorizontalScrollBarVisibility="Auto"> <ItemsPresenter /> <!-- The ItemsPresenter creates the Panels for the layout ofr hte Items based on what is specified by the ItemsPanelTemplate --> </ScrollViewer> </Border> </ControlTemplate> </Setter.Value> </Setter> </Style>
主函数如下
In general, the Main code is as such
[STAThread] [DebuggerNonUserCode] public static void Main(string[] args) { App app = new App(); //app.InitializeComponent(); app.Run(new MainWindow()); }
在主窗口的 代码种,加入如下的Page代码(ListBox写在Page里面).
And in the MainWindow, do things like this for the pages that contains the ListBox with Customizing Styles.
<page:HorizontalListBoxPage VerticalAlignment="Stretch" HorizontalAlignment="Stretch" Height="300" Width="450" xmlns:page="clr-namespace:DemoItemsPanelTemplate" ></page:HorizontalListBoxPage>
Or
<page:HorizontalLisBoxWithControlTemplatePage VerticalAlignment="Center" HorizontalAlignment="Center" Height="300" Width="450" xmlns:page="clr-namespace:DemoItemsPanelTemplate"></page:HorizontalLisBoxWithControlTemplatePage>
Or
<page:ControlAndItemsPanelTemplatePage VerticalAlignment="Center" HorizontalAlignment="Center" Height="300" Width="450" xmlns:page="clr-namespace:DemoItemsPanelTemplate" ></page:ControlAndItemsPanelTemplatePage>
引用:
References: