In one of my first posts I showed how to develop a simple grid with a ListView using an ObservableCollection as source. But if you start to add some UI modifications to your app maybe you can find a few problems.
I’ll create a situation that you’ll surely will be in someday. Let’s say that one of the properties of your class is changing, and somehow you want to show a notification and you decide change the background and the foreground for that row. You have an event and a handler in your code behind so you know the index of the item changed.
Now you have a problem, if you use this: “ListView.Items[index]” you WILL NOT get a ListViewItem as you may be thinking, what you will get is the data source for the item. What do I want to say? if your source is something like this:
ObservableCollection<YourClass>
What you will get with this: “ListView.Items[index]” is an object of type YourClass. What we need is the ListViewItem which has the Background and Foreground. I used the ItemContainerGenerator property of the ListView and the ContainerFromIndex method to accomplish this.
ListView rocks! hehehe, and finally… the code:
<Window x:Class=”BlogStuff.Window1″
xmlns=”http://schemas.microsoft.com/winfx/2006/xaml/presentation”
xmlns:x=”http://schemas.microsoft.com/winfx/2006/xaml”
Title=”My Simple Grid” Height=”300″ Width=”300″>
<ListView ItemsSource=”{Binding}” x:Name=”lv”>
<ListView.View>
<GridView>
<GridViewColumn Header=”Name” DisplayMemberBinding=”{Binding Path=Name}”>
<GridViewColumn.CellTemplate>
<DataTemplate>
<Label/>
</DataTemplate>
</GridViewColumn.CellTemplate>
</GridViewColumn>
<GridViewColumn Header=”Age” DisplayMemberBinding=”{Binding Path=Age}”>
<GridViewColumn.CellTemplate>
<DataTemplate>
<Label/>
</DataTemplate>
</GridViewColumn.CellTemplate>
</GridViewColumn>
<GridViewColumn Header=”Random Number” DisplayMemberBinding=”{Binding Path=RandomNumber}”>
<GridViewColumn.CellTemplate>
<DataTemplate>
<Label/>
</DataTemplate>
</GridViewColumn.CellTemplate>
</GridViewColumn>
</GridView>
</ListView.View>
</ListView>
</Window>
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;
//Added by me:
using System.Collections.ObjectModel;
using System.Windows.Threading;
using System.ComponentModel;
namespace BlogStuff
{
/// <summary>
/// Interaction logic for Window1.xaml
/// </summary>
public partial class Window1 : Window
{
//This is our source, every item in this collection represents a row in the grid
ObservableCollection<Guest> guests = new ObservableCollection<Guest>();
//Generator for random numbers
Random gen = new Random(DateTime.Now.Millisecond);
//Timer used to change the value of the RandomNumber property every second
DispatcherTimer timer = new DispatcherTimer();
public Window1()
{
InitializeComponent();
//This line is our connection to the UI
//the collection is setted as the source for the listview
lv.DataContext = guests;
timer.Interval = TimeSpan.FromMilliseconds(1000);
timer.Tick += new EventHandler(timer_Tick);
//Here we add three elements to the collection and instantly three rows are
//builded on the grid –>
guests.Add(new Guest()
{
Name = “Fernando Romero”,
Age = 23,
RandomNumber = gen.Next(100)
});
guests.Add(new Guest()
{
Name = “Luis Del Vasto”,
Age = 22,
RandomNumber = gen.Next(100)
});
guests.Add(new Guest()
{
Name = “Nestor Martinez”,
Age = 26,
RandomNumber = gen.Next(100)
});
// <–
timer.Start();
}
//We store a reference to tha last row changed in order to restore the
//default settings on it
Control lastRowChanged;
private void timer_Tick(object sender, EventArgs e)
{
//We select one of the items randomly and we change its RandomNumber property
int index = gen.Next(3);
guests[index].RandomNumber = gen.Next(100);
//Restore default settings on previous changed row (just one row should be
//highlighted in this example)
if (lastRowChanged != null)
{
lastRowChanged.Background = Brushes.White;
lastRowChanged.Foreground = Brushes.Black;
}
//We retrieve the ItemContainerGenerator object from the ListView and we call
//the ContainerFromIndex method to get the ListViewItem, once we get it we can change
//the background and foreground properties
lastRowChanged = lv.ItemContainerGenerator.ContainerFromIndex(index) as ListViewItem;
lastRowChanged.Background = Brushes.LightGreen;
lastRowChanged.Foreground = Brushes.Red;
}
}
public class Guest : INotifyPropertyChanged
{
public string Name { get; set; }
public int Age { get; set; }
int randomNumber;
public int RandomNumber
{
get { return randomNumber; }
set
{
if (value != randomNumber)
{
randomNumber = value;
if (PropertyChanged != null) PropertyChanged(this, new PropertyChangedEventArgs(“RandomNumber”));
}
}
}
#region INotifyPropertyChanged Members
public event PropertyChangedEventHandler PropertyChanged;
#endregion
}
}

Eunice said,
March 26, 2008 at 2:21 pm
hi fernando,
i’m doing a WPF project at the moment, but i am facing difficulties with binding and stuff.
Suppose there are multiple listviewitems, and what i want to do is to bind any listviewitem to an object everytime a user click one.
Can you help with that??
thanks in advance.
fernandojhoel said,
March 26, 2008 at 6:39 pm
Hi Eunice, thanks for you comment!
Before trying to solve the problem let me see if I understand. You a have Listview with multiple ListViewItems already created and when an user click on one of them you want to bind this ListViewItem to an object. Mmm, I would like to know if at the beginning there is a binding to the entire ListView and what you want to do is just change the source for that specific row, is important to know if you are using the ItemsSource property of the ListView.
I’ll make some experiments and then I’ll post my results in order to help you. Just wait a little
Eunice said,
March 31, 2008 at 7:29 am
Hi joel, thanks for your reply.
At the moment, there is no binding to the entire ListView at the beginning, but I’m planning to bind it from an XML file.
Well, is there any other way to make a simple grid? Up to now, i’m still using Table from FlowDocumentScrollViewer and I’m stuck with the binding stuff.
I’ll wait for your reply..Thx in advance..
vilas said,
February 11, 2009 at 4:55 pm
Hi Joel, nice post. I am trying to get a individual record object on the mouse move on the Binded ListView. I am able to set the listviewitem control properties using control triggers, but to get the data seems to be not working.