Rounded Items and alternate backgrounds in a Listview

One of the hardest things in WPF it’s that there are many ways to reach the same result. The same is true with other frameworks, but WPF and its language, XAML, allow for some powerful and complex design with a large collection of concepts : dependency properties , attached properties, control templates, item templates, styles and so on… I’m currently writing a simple Twitter viewer as a way to learn WPF. This “application” simply shows the xml-based feed of a user’s friends through the API :

image
image

I created classes from the feed through the XSD schema generation tool (xsd.exe). Be careful before splitting the generated classes, read the Serialization section on MSDN :

classDiagram
classDiagram

A helper class creates an HTTP request with basic authentication to get the feed :

//object to hold twitter response Statuses statuses = null; //request to twitter service HttpWebRequest request = (HttpWebRequest)
WebRequest.Create(“http://twitter.com/statuses/friends_timeline.xml”); //authentication info CredentialCache authInfo = new CredentialCache(); authInfo.Add(new Uri(http://twitter.com/statuses/friends_timeline.xml),
“Basic”, new NetworkCredential(username, password)); request.Credentials = authInfo; //make the call WebResponse response = request.GetResponse(); //deserialize response XmlSerializer mySerializer = new XmlSerializer(typeof(Statuses)); statuses = (Statuses)mySerializer.Deserialize(response.GetResponseStream());

response.Close(); listStatut = new List<Status>(statuses.status);

This method is called by the ObjectDataProvider which provides the user and password :

<ObjectDataProvider x:Key=“TwitterDataSource” d:IsDataSource=“True” ObjectType="{x:Type TwitterWPF:TwitterManager}" MethodName=“GetStatuses”> <ObjectDataProvider.ConstructorParameters> sys:String\user</sys:String> sys:String\password</sys:String> </ObjectDataProvider.ConstructorParameters> </ObjectDataProvider>

This class puts the collection returned in an ObservableCollection object that provides notification when an item is added or removed. This can be useful since we want to refresh the UI with a timer to get new statuses from Twitter.

I found several articles to design items with alternate backgrounds in a ListView but none works for me. They overwrite the style property of the items and they will hide the background of the border. This border is used to simulate rounded panels around the text :

<ListView.ItemTemplate> <DataTemplate> <Border Width=“400” Height=“75” CornerRadius=“10,10,10,10” Margin=“4,4,4,4” Padding=“4,4,4,4” Background="{Binding RelativeSource={RelativeSource AncestorType=ListViewItem},
Converter={StaticResource backgroundConverter}}"> <Grid x:Name=“statusBox” Height=“auto” Width=“auto”> <Grid.ColumnDefinitions> <ColumnDefinition Width=“0.168*” /> <ColumnDefinition Width=“0.832*” /> </Grid.ColumnDefinitions> <Grid.RowDefinitions> </Grid.RowDefinitions> <Image Source="{Binding Path=User.ProfileImageUrl}" Grid.Column=“0” Grid.Row=“0” x:Name=“userImage”/> <Label Margin=“8,0,8,0” x:Name=“status” Grid.Column=“1” > <TextBlock TextWrapping=“WrapWithOverflow” Text="{Binding Path=Text}"></TextBlock> </Label> </Grid> </Border> </DataTemplate> </ListView.ItemTemplate>

image
image

So I built an implementation of IValueConverter to convert the binding of the background value property. I need to know the current ListViewItem, so I provide the ancestor of type ListViewItem as the object to be converted. The converter class finds its index inside the ListView and returns the color accordingly :

public object Convert(object value, Type targetType,
object parameter, System.Globalization.CultureInfo culture) { ListViewItem item = (ListViewItem)value; ListView listView = ItemsControl.ItemsControlFromItemContainer(item) as ListView; // Get the index of a ListViewItem int index = listView.ItemContainerGenerator.IndexFromContainer(item);

  if (index % 2 == 0)
  {
    return Brushes.LightBlue;
  }
  else
  {
    return Brushes.Beige;
  }

}

The last thing to add is the call to refresh the list of the statuses : I put a timer that refreshes both the  ObjectDataProvider and the ListView (without the latter the index property is not correctly returned in the converter method) :

void TimerClock_Tick(object sender, EventArgs e) { ObjectDataProvider odp = Resources[“TwitterDataSource”] as ObjectDataProvider; odp.Refresh(); ICollectionView dataView = CollectionViewSource.GetDefaultView(statusList.ItemsSource); dataView.Refresh(); }

As I said, there are surely other ways to do this, maybe even more efficiently. But the Twitter API returning only the 20 latest statuses,  efficiently is not an issue. And it’s a good thing because I’m still discovering the WPF world.

download the Visual Studio Orcas solution (beta1).

Technorati Tags: wpf, listview, rounded, [alternate background](http://technorati.com/tags/alternate background)

Billet publié dans les rubriques Programmation le