Skip to main content

C# - Using The ListView, Part 1 In WPF [Beginner]


Many of the controls in WPF have a downright dizzying array of capabilities and features, due in large part to the composibility of all the components. The ListView control is a great example of this - the possibilities are almost endless. This series of tutorials on the ListView will hopefully make the space of possible options seem not quite as daunting.

We will be starting today with a simple grid based list view, showing how to create columns and some different ways of getting data into those columns. This tutorial won't be very exciting - we will mostly just be setting up the basics for use in some of the later parts. Hopefully, the series will culminate in a sort of "DataGridView" for WPF (a control that, sadly, does not yet exist in WPF). I say hopefully cause I haven't yet written the code for those parts :

OK, so here's a screenshot of a ListView with a few columns and no data. Nothing really fancy, but the basic starting point.

Empty ListView

The code to create this is just as boring:
<Window x:Class="ListViewTest.Test0.ListViewTest" 
    xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
    xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
    Title="Empty ListView Grid" Height="216" Width="435">
 <ListView>
  <ListView.View>
   <GridView>
    <GridViewColumn Width="140" Header="Column 1" />
    <GridViewColumn Width="140" Header="Column 2" />
    <GridViewColumn Width="140" Header="Column 3" />
   </GridView>
  </ListView.View>
 </ListView>
</Window>
 
The special code here is in the ListView.View section. This is what changes the list view from your standard wrapping list of items into something else - in this case a GridView. Don't confuse the GridView with the standard WPF Grid control - they are very different. Pretty much the only thing that is the same is that they both have the word Grid in the name.

So we make a GridView and then we make a couple GridViewColumns. These GridViewColumns have a lot more functionality than is used here - we will start to see that in the later examples and especially in later tutorials. There are a couple nice things that you automatically get with the GridView and GridViewColumns - first off, the columns can be resized by the user exactly like, say, the columns in Windows Explorer. Also, the user can drag+drop to reorder columns, and you don't have to worry about it at all. One thing that is missing, though, is some built in sorting capability - but it isn't that hard to add on (we will be doing that in a later tutorial).

OK, enough about that. Lets throw some data into this grid!

Listview with
dates

And heres the xaml code:
<Window x:Class="ListViewTest.Test1.ListViewTest"
    xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
    xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
    xmlns:sys="clr-namespace:System;assembly=mscorlib"
    Title="Some Dates" Height="216" Width="435">  
  <ListView>
    <ListView.View>
      <GridView>
        <GridViewColumn Width="120" Header="Date" />
        <GridViewColumn Width="120" Header="Day Of Week"  
            DisplayMemberBinding="{Binding DayOfWeek}" />
        <GridViewColumn Width="120" Header="Year" 
            DisplayMemberBinding="{Binding Year}" />
      </GridView>
    </ListView.View>
    <sys:DateTime>1/2/3</sys:DateTime>
    <sys:DateTime>4/5/6</sys:DateTime>
    <sys:DateTime>7/8/9</sys:DateTime>
    <sys:DateTime>10/11/12</sys:DateTime>
  </ListView>
</Window>
 
So there are a couple changes to the xaml here. First, I imported the System namespace and registered it to "sys", because I wanted to use some DateTime objects as my ListView data. Next, you can see that two of the GridViewColumns have a DisplayMemberBinding property now. And finally, there are the 4 dates which are the data for the ListView.

The only part that probably needs explaining is the DisplayMemberBinding property. This property tells the column what data from an entry should be displayed in that column. As you can see, the first column does not have this property set, so it just does a toString on the date object for each row to determine what to put in that column. The second column is bound to the DayOfWeek property on the DateTime object - and so in that column the day of the week for each of those dates is printed. And for the third column, we have bound to the Year property, and so we get the year out. Pretty cool, eh?
Now you're probably thinking thats all well and good, but you want to display your own data objects, and you want to be able to add and remove them on the fly. No worries there - the ListView has got you covered!

Listview with games

Here we make a departure for using just XAML - there is actually (gasp!) some C# code behind. So lets take a look:
<Window x:Class="ListViewTest.Test2.ListViewTest"
    xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
    xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
    DataContext="{Binding RelativeSource={RelativeSource Self}}"
    Title="Some Game Data" Height="216" Width="435">
  <StackPanel>
    <ListView ItemsSource="{Binding GameCollection}">
      <ListView.View>
        <GridView>
          <GridViewColumn Width="140" Header="Game Name" 
              DisplayMemberBinding="{Binding GameName}"  />
          <GridViewColumn Width="140" Header="Creator"  
              DisplayMemberBinding="{Binding Creator}" />
          <GridViewColumn Width="140" Header="Publisher" 
              DisplayMemberBinding="{Binding Publisher}" />
        </GridView>
      </ListView.View>
    </ListView>
    <Button HorizontalAlignment="Right" Margin="5,5,5,5" 
        Content="Add Row" Click="AddRow_Click" />
  </StackPanel>
</Window>
 
And the code behind:
using System;
using System.Windows;
using System.Windows.Controls;
using System.Collections.ObjectModel;

namespace ListViewTest.Test2
{
  public partial class ListViewTest : Window
  {
    ObservableCollection<GameData> _GameCollection = 
        new ObservableCollection<GameData>();

    public ListViewTest()
    {
      _GameCollection.Add(new GameData { 
          GameName = "World Of Warcraft", 
          Creator = "Blizzard", 
          Publisher = "Blizzard" });
      _GameCollection.Add(new GameData { 
          GameName = "Halo", 
          Creator = "Bungie", 
          Publisher = "Microsoft" });
      _GameCollection.Add(new GameData { 
          GameName = "Gears Of War", 
          Creator = "Epic", 
          Publisher = "Microsoft" });

      InitializeComponent();
    }

    public ObservableCollection<GameData> GameCollection
    { get { return _GameCollection; } }

    private void AddRow_Click(object sender, RoutedEventArgs e)
    {
      _GameCollection.Add(new GameData { 
          GameName = "A New Game", 
          Creator = "A New Creator", 
          Publisher = "A New Publisher" });
    }
  }

  public class GameData
  {
    public string GameName { get; set; }
    public string Creator { get; set; }
    public string Publisher { get; set; }
  }
}
 
So what we have here is a set of GameData objects that we want to display in the ListView. The GameData objects have a Game Name, a Creator, and a Publisher, and so we create three columns in the ListView and bind them each to the appropriate fields. One thing to note - and I'll probably elaborate on this more if I ever get around to a tutorial on WPF Binding - you can only bind to public properties/methods/dependency properties. You can't bind to private things, or to fields. The syntax I used in the GameData class right above is syntactic sugar for not having to write out the full property definition. When the code is compiled, those lines for GameName, etc., turn into properties with a backing private field.

So we have some GameData objects - how do we get them into the ListView? Well, we create an ObservableCollection of them. ObservableCollection is not your normal everyday generic list - it can tell other pieces of code when the contents of the collection change. You'll see why this comes in handy in a moment.

Now that we have this collection (and we have created a public field for it) what do we do with it? Well, we bind it as the ItemsSource of the ListView. This is where the fact that the collection is observable comes in handy - now the ListView gets alerted whenever anything changes inside of the collection, and can update accordingly. For example, when you press the "Add Row" button, a new GameData instance is added to the collection. The ListView is notified, and so is able to update and display the new row.

OK, well that is it for this first tutorial on the WPF ListView. You can get the source code for all three examples here if you would like it. Stay tuned for future tutorials on the ListView, covering topics like sorting, filtering, and how to configure the look of the cells in the view.
Source Files:

Comments

Popular posts from this blog

C# Snippet - Shuffling a Dictionary [Beginner]

Randomizing something can be a daunting task, especially with all the algorithms out there. However, sometimes you just need to shuffle things up, in a simple, yet effective manner. Today we are going to take a quick look at an easy and simple way to randomize a dictionary, which is most likely something that you may be using in a complex application. The tricky thing about ordering dictionaries is that...well they are not ordered to begin with. Typically they are a chaotic collection of key/value pairs. There is no first element or last element, just elements. This is why it is a little tricky to randomize them. Before we get started, we need to build a quick dictionary. For this tutorial, we will be doing an extremely simple string/int dictionary, but rest assured the steps we take can be used for any kind of dictionary you can come up with, no matter what object types you use. Dictionary < String , int > origin = new Dictionary < string , int >(); ...

C# WPF Printing Part 2 - Pagination [Intermediate]

About two weeks ago, we had a tutorial here at SOTC on the basics of printing in WPF . It covered the standard stuff, like popping the print dialog, and what you needed to do to print visuals (both created in XAML and on the fly). But really, that's barely scratching the surface - any decent printing system in pretty much any application needs to be able to do a lot more than that. So today, we are going to take one more baby step forward into the world of printing - we are going to take a look at pagination. The main class that we will need to do pagination is the DocumentPaginator . I mentioned this class very briefly in the previous tutorial, but only in the context of the printing methods on PrintDialog , PrintVisual (which we focused on last time) and PrintDocument (which we will be focusing on today). This PrintDocument function takes a DocumentPaginator to print - and this is why we need to create one. Unfortunately, making a DocumentPaginator is not as easy as...

C# WPF Tutorial - Implementing IScrollInfo [Advanced]

The ScrollViewer in WPF is pretty handy (and quite flexible) - especially when compared to what you had to work with in WinForms ( ScrollableControl ). 98% of the time, I can make the ScrollViewer do what I need it to for the given situation. Those other 2 percent, though, can get kind of hairy. Fortunately, WPF provides the IScrollInfo interface - which is what we will be talking about today. So what is IScrollInfo ? Well, it is a way to take over the logic behind scrolling, while still maintaining the look and feel of the standard ScrollViewer . Now, first off, why in the world would we want to do that? To answer that question, I'm going to take a an example from a tutorial that is over a year old now - Creating a Custom Panel Control . In that tutorial, we created our own custom WPF panel (that animated!). One of the issues with that panel though (and the WPF WrapPanel in general) is that you have to disable the horizontal scrollbar if you put the panel in a ScrollV...