-- Reprint and code implementation of WPF virtualization

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.


 

 

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值