`

-- Reprint and code implementation of WPF virtualization

    博客分类:
  • WPF
阅读更多

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.


 

 

  • 大小: 26.6 KB
分享到:
评论

相关推荐

Global site tag (gtag.js) - Google Analytics