Page 1 of 1

Virtual Item Controls How do you display 1000's of items in a ListBox in WPF?

#1 StCroixSkipper  Icon User is offline

  • D.I.C Head
  • member icon

Reputation: 10
  • View blog
  • Posts: 121
  • Joined: 23-December 08

Posted 28 April 2010 - 03:06 PM

I've seen this question posted all over the net and the answers miss the mark. Perhaps it is too simple.

The problem: I have ~ 58 thousand directories on my C drive. How do I display them efficiently in an 'Item Control' like a ListBox?

The answer: Build your collection of items to display. Assign the collection to the Item Control's ItemSource property.

That is the easy explanation.

So lets create a list of FileInfo objects by enumerating all the files in a directory with lots of files. And lets get all the files in all the sub directories too. I'm going to use my 'Pictures' directory since I have tons of files in that directory.

First create a project in Visual Studio. I called mine 'Virtual ListBox Project'. I use a 'Grid' and create two Columns and one Row.

In the first column I add some buttons, one to build a list of files, another to display the list of files in a 'virtual' ListBox and another to display the list of files by creating a ListBoxItem for each file and adding it to the ListBox.

Here is the xaml code.
<Window x:Class="VirtualListBoxProject.Window1"
    xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
    xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
    Title="Window1" Height="300" Width="500">
    <Grid>
        <Grid.ColumnDefinitions>
            <ColumnDefinition Width="150"/>
            <ColumnDefinition Width="*"/>
        </Grid.ColumnDefinitions>
        <Grid.RowDefinitions>
            <RowDefinition Height="*"/>
        </Grid.RowDefinitions>
        <DockPanel Name="usnButtonStack" Background="AliceBlue">
            <Button Name="BuildList" Grid.Column="0" Margin="5,5,5,2.5" Content="Build File List" 
                    Click="BuildList_Click" DockPanel.Dock="Top" VerticalAlignment="Top" IsEnabled="True"/>
            <Button Name="DisplayListVirtual" Grid.Column="0" Margin="5,5,5,2.5" Content="Display List Virtual" 
                    Click="DisplayListVirtual_Click" DockPanel.Dock="Top" VerticalAlignment="Top" IsEnabled="False"/>
            <Button Name="DisplayListNormal" Grid.Column="0" Margin="5,5,5,2.5" Content="Display List Normal" 
                    Click="DisplayListNormal_Click" DockPanel.Dock="Top" VerticalAlignment="Top" IsEnabled="False"/>
        </DockPanel>
        <DockPanel Name="resultsDock" Grid.Column="1" Grid.Row="0" >
            <Label Name="FunctionElapsedTime" Content="Function And Elapsed Time" DockPanel.Dock="Top" Foreground="DarkBlue"/>
            <ListBox Name="resultsLb" Selectionchanged="resultsLb_Selectionchanged" 
                     ScrollViewer.VerticalScrollBarVisibility="Auto" 
                     Background="AliceBlue"
                     DockPanel.Dock="Top"
                     SelectionMode="Single"
                     PreviewMouseDown="resultsLb_PreviewMouseDown">
                <ListBox.ItemTemplate>
                    <DataTemplate>
                        <StackPanel>
                            <TextBlock Text="{Binding Path=Name}"/>
                        </StackPanel>
                    </DataTemplate>
                </ListBox.ItemTemplate>
            </ListBox>
        </DockPanel>
    </Grid>
</Window>



Notice that I add a DataTemplate which sets the TextBox's Text property to "{Binding Path=Name}" and essentially assign it to the ListBox.ItemTemplate. That essentially says that whatever the the elements in the list you assign to ListBox.ItemSource are, take the Name property and display it as the item in the ListBox. (I agree the StackPanel is not necessary. It is just the way I wrote the code.)

Here is the Window1.xaml.cs 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.IO;

namespace VirtualListBoxProject
{
    /// <summary>
    /// Interaction logic for Window1.xaml
    /// </summary>
    public partial class Window1 : Window
    {
        private List<FileInfo> _FileList;
        public Window1()
        {
            InitializeComponent();
        }

        private void BuildList_Click(object sender, RoutedEventArgs e)
        {
            DateTime start = DateTime.Now;
            _FileList = new List<FileInfo>();
            string[] files = Directory.GetFiles("C:\\Users\\Scott\\Pictures", "*.*", SearchOption.AllDirectories);
            foreach (string file in files)
            {
                _FileList.Add(new FileInfo(file));
            }
            TimeSpan elapsedTime = DateTime.Now - start;
            FunctionElapsedTime.Content = string.Format("Elapsed time in milliseconds: {0}", elapsedTime.Milliseconds);
            DisplayListNormal.IsEnabled = true;
            DisplayListVirtual.IsEnabled = true;
        }

        private void DisplayListVirtual_Click(object sender, RoutedEventArgs e)
        {
            DateTime start = DateTime.Now;
            resultsLb.ItemsSource = null;
            resultsLb.Items.Clear();
            resultsLb.ItemsSource = _FileList;
            TimeSpan elapsedTime = DateTime.Now - start;
            FunctionElapsedTime.Content = string.Format("Elapsed time in milliseconds: {0}", elapsedTime.Milliseconds);
        }

        private void DisplayListNormal_Click(object sender, RoutedEventArgs e)
        {
            DateTime start = DateTime.Now;
            resultsLb.ItemsSource = null;
            resultsLb.Items.Clear();
            foreach (FileInfo fi in _FileList)
            {
                ListBoxItem item = new ListBoxItem();
                item.Content = fi.Name;
                resultsLb.Items.Add(item);
            }
            TimeSpan elapsedTime = DateTime.Now - start;
            FunctionElapsedTime.Content = string.Format("Elapsed time in milliseconds: {0}", elapsedTime.Milliseconds);
        }

        private void resultsLb_Selectionchanged(object sender, SelectionchangedEventArgs e)
        {

        }

        private void resultsLb_PreviewMouseDown(object sender, MouseButtonEventArgs e)
        {

        }
    }
}



The resultsLb_Selectionchanged() and resultsLb_PreviewMouseDown() functions are also superfluous but they are there so you can position and fill a popup window with the FileInfo information if you choose.

Now you can fill the ListBox by pressing the 'Build File List' button and see the elapsed time in milliseconds displayed at the top of the ListBox.

Pressing the 'Display List Virtual' button simply assigns the FileInfo list to the ListBox's ItemSource property and displays the time it took in milliseconds.

Pressing the 'Display List Normal' button creates a ListBoxItem for each FileInfo object in the file list and adds it to the ListBox and then displays the elapsed time in milliseconds.

For a list of any length, you should see a dramatic difference in time.

Is This A Good Question/Topic? 0
  • +

Replies To: Virtual Item Controls

#2 StCroixSkipper  Icon User is offline

  • D.I.C Head
  • member icon

Reputation: 10
  • View blog
  • Posts: 121
  • Joined: 23-December 08

Posted 24 May 2010 - 08:31 AM

This title should have been 'Virtual Items Control' It's really a virtual ListBox to display 1000's of items. - Sorry
Was This Post Helpful? 0
  • +
  • -

Page 1 of 1