Followed by the copy of the blog on?http://bea.stollnitz.com/blog/?p=338?(with title of UI Virtualization), Joe has created his own blog with some connotation.?
?
?
The article from the original post does not include the code, in this blog, I have implemented some code which can demonstrate the use of the technique that has been inroduced.
?
In summary, the following technique has been inroduced
?
?
- VirtualizingStackPanel to ItemsPaneTemplate
- Container Recycling
- Deferred Scrolling
- UI Virtualizing extended to Hierarchical Data structure, such as the TreeView
?
?
Below shows the Xaml definition and the code behind source code (in C#)
?
?
?
The xaml code?
?
<Window x:Class="Virtualization.MainWindow" xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation" xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml" xmlns:local="clr-namespace:Virtualization" Title="MainWindow" Height="650" Width="700" > <!-- this template is copying from the twiki of http://vbcity.com/blogs/xtab/archive/2009/11/25/wpf-how-to-list-select-and-apply-fonts.aspx with the title of WPF: How To List, Select and Apply Fonts --> <Window.Resources> <DataTemplate x:Key="FontDisplay"> <TextBlock Text="{Binding}" FontFamily="{Binding}" FontSize="14" /> </DataTemplate> </Window.Resources> <StackPanel> <!-- the ComboBox that has no data virtualization --> <ComboBox x:Name="CombFonts" ItemsSource="{Binding}" Margin="4,22,9,27" ItemTemplate="{StaticResource FontDisplay}" > </ComboBox> <Separator /> <TextBlock Margin="6,10, 0, 1" Text="Combo with VirualizingStackPanel as ComboBox.ItemsPanel" HorizontalAlignment="Left" VerticalAlignment="Center" FontWeight="Bold" /> <!-- --> <ComboBox x:Name="CombFonts2" ItemsSource="{Binding}" Margin="4,22,9,27" ItemTemplate="{StaticResource FontDisplay}" > <ComboBox.ItemsPanel> <ItemsPanelTemplate> <VirtualizingStackPanel /> </ItemsPanelTemplate> </ComboBox.ItemsPanel> </ComboBox> <Separator /> <TextBlock Margin="6,10, 0, 1" Text="ListBox with Container recyling" HorizontalAlignment="Left" VerticalAlignment="Center" FontWeight="Bold" /> <!-- the following demonstrate the use of the VirtualizingMode in VirtualizingStackPanel The comment is based on the article http://bea.stollnitz.com/blog/?p=338 section Container recycling the principle/foundation of the Container recycle is as follow. 30 ListBoxItems are created to display the visible data. When the user scrolls the ListBox, instead of discarding ListBoxItems that scroll out of view and creating new ones for the data items that scroll into view, WPF reuses the existing ListBoxItems, So basically it is the ListBoxItems reuse. There are two values of the VirtualizationMode, they are * Recyling * Standard To maintain the backword compatibility with the behavior of the earlier versions, container recycling is disable by default (the default VirtualizationMode is "Standard") --> <ListBox VirtualizingStackPanel.VirtualizationMode="Recycling" ItemsSource="{Binding}" ItemTemplate="{StaticResource FontDisplay}" ScrollViewer.VerticalScrollBarVisibility="Visible" ScrollViewer.HorizontalScrollBarVisibility="Auto" Height="100" > </ListBox> <Separator /> <TextBlock Margin="6,10, 0, 1" Text="ListBox with Defered Scrolling" HorizontalAlignment="Left" VerticalAlignment="Center" FontWeight="Bold" /> <!-- “Deferred scrolling” is a feature that allows the user to drag the scroll bar thumb around without changing the displayed items until the scroll bar thumb is released. --> <ListBox ScrollViewer.IsDeferredScrollingEnabled="True" ItemsSource="{Binding}" ItemTemplate="{StaticResource FontDisplay}" ScrollViewer.VerticalScrollBarVisibility="Visible" ScrollViewer.HorizontalScrollBarVisibility="Auto" Height="100" /> <Separator /> <TextBlock Margin="6,10, 0, 1" Text="Hierarchical Data with IsVirtualizing=True" HorizontalAlignment="Left" VerticalAlignment="Center" FontWeight="Bold" /> <!-- Since the advent of .NET framework 3.5, the team has added the Virutalization Support to the Hierarchical structure, such as the TreeView So use the virtualization, you can need to do is to set the following tags VirtualizingStackPanel.IsVirtualizing="True" But if you want to have more control on the Data virtualization, I would suggest you take a look at the example of TreeView3 --> <TreeView ItemsSource="{Binding Path=RootKeys}" VirtualizingStackPanel.IsVirtualizing="True" x:Name="TreeViewRegistry" ScrollViewer.VerticalScrollBarVisibility="Visible" ScrollViewer.HorizontalScrollBarVisibility="Auto" Height="100" > <TreeView.Resources> <HierarchicalDataTemplate DataType="{x:Type local:RegistryKeyHolder1}" ItemsSource="{Binding Path=SubKeys}"> <TextBlock Text="{Binding Path=ShortName}" /> </HierarchicalDataTemplate> </TreeView.Resources> </TreeView> </StackPanel> </Window>?
?
?
?
The C# code
?
using System; using System.Collections.Generic; using System.Linq; using System.Text; using System.Windows; using System.Windows.Controls; using System.Windows.Data; using System.Windows.Documents; using System.Windows.Input; using System.Windows.Media; using System.Windows.Media.Imaging; using System.Windows.Navigation; using System.Windows.Shapes; using System.Security.Permissions; using System.Security; using System.Collections.ObjectModel; using Microsoft.Win32; namespace Virtualization { [assembly: RegistryPermissionAttribute(SecurityAction.RequestMinimum, Read = "HKEY_CURRENT_CONFIG")] [assembly: RegistryPermissionAttribute(SecurityAction.RequestMinimum, Read = "HKEY_CURRENT_USER")] /// <summary> /// Interaction logic for MainWindow.xaml /// </summary> public partial class MainWindow : Window { public MainWindow() { InitializeComponent(); InitializeDataContextToSystemFonts(); InitializeTreeViewDataSourceToRegistries(); } private void InitializeDataContextToSystemFonts() { this.DataContext = Fonts.SystemFontFamilies; } private void InitializeTreeViewDataSourceToRegistries() { this.TreeViewRegistry.DataContext = new RegistryData1(); } } #region TreeView Data // this TreeView data is copied from the previous example on the TreeViews. // since we want to make the TreeView simple, so we take the example from // TreeView1. which does not have UI Virtualization and no DataVirtualization // #region Data - No UI visualization, no data virtualization public class RegistryData1 { private ObservableCollection<RegistryKeyHolder1> rootKeys; private int dataItemsCount; /// <summary> /// The root keys, such as HKEY_CURRENT_CONFIG, or HKEY_CURRENT_USER /// </summary> public ObservableCollection<RegistryKeyHolder1> RootKeys { get { return rootKeys; } } /// <summary> /// Total number of items that has been populated /// </summary> public int DataItemsCount { get { return dataItemsCount; } } public RegistryData1() { this.rootKeys = new ObservableCollection<RegistryKeyHolder1>(); rootKeys.Add(new RegistryKeyHolder1(Registry.CurrentUser)); rootKeys.Add(new RegistryKeyHolder1(Registry.CurrentConfig)); this.dataItemsCount = 2; PopulateSubKeys(this.rootKeys); } private void PopulateSubKeys(ObservableCollection<RegistryKeyHolder1> keys) { foreach (RegistryKeyHolder1 keyHolder in keys) { // expand each of the subkeys keyHolder.PopulateSubKeys(); this.dataItemsCount += keyHolder.SubKeys.Count; // set a hard limit so that we don't blow if (this.dataItemsCount >= 5000) { return; } PopulateSubKeys(keyHolder.SubKeys); } } } /// <summary> /// Registry Key Holder /// </summary> public class RegistryKeyHolder1 { private RegistryKey key; private ObservableCollection<RegistryKeyHolder1> subKeys; public RegistryKey Key { get { return key; } } public string ShortName { get { return key.Name.Substring(key.Name.LastIndexOf('\\') + 1); } } public ObservableCollection<RegistryKeyHolder1> SubKeys { get { return subKeys; } } public RegistryKeyHolder1(RegistryKey key) { this.key = key; this.subKeys = new ObservableCollection<RegistryKeyHolder1>(); } /// <summary> /// Populate <paramref name="this"/> SubKeys collection /// </summary> /// <remarks> /// Lazy populate the subkeys </remarks> public void PopulateSubKeys() { try { string[] subKeyNames = this.key.GetSubKeyNames(); for (int i = 0; i < subKeyNames.Length; ++i) { this.subKeys.Add(new RegistryKeyHolder1(this.key.OpenSubKey(subKeyNames[i]))); } } catch (SecurityException ex) { System.Console.WriteLine(ex.Message); } } } #endregion Data - No UI visualization, no data virtualization #endregion TreeView Data }?
?
?
and below shows the snapshot of the application in action.
?