« This is your brain on .NET... any questions?PrintTicket provider failed to retrieve PrintCapabilities »

Alternating row styles in a ListBox

10/14/08

Permalink 12:29:55 pm, Categories: WPF

Background

In WPF, there are often many ways of accomplishing the same end result. I recommend always looking for the most "correct" solution, and that in my opinion is the one that most naturally fits in with the framework hooks already provided, as well as being the most generic and reusable solution possible.

The Problem

Simple. How do I implement alternating row styles in a ListBox?

Building Blocks

The following, provided in the framework, will be useful:

My Solution

You may have noticed that the relevant framework hooks do not refer to the ListBox class, but rather the shared base of ItemsControl.

So while we could write an alternating row style selector for a ListBox, why not write a more generic item style selector for any ItemsControl? (The term "item" is important even within the context of only the ListBox, because a ListBox need not even be displayed in a row format; it can in fact be styled to render in any number of configurations.)

Note that because of the way styles work in WPF, we will have to specialize the Style instances themselves when we use the selector. We'll see that later.

Implementing the StyleSelector

All we really require of the StyleSelector is to hold two styles and switch between them for every other item in the ItemsControl.

using System.Windows;
using System.Windows.Controls;


public class ItemsControlAlternatingStyleSelector : StyleSelector
{
    Style evenStyle, oddStyle;

    public Style EvenStyle {
        get {
            return evenStyle;
        }
        set {
            evenStyle = value;
        }
    }

    public Style OddStyle {
        get {
            return oddStyle;
        }
        set {
            oddStyle = value;
        }
    }

    public override Style SelectStyle(object item, DependencyObject container) {
        ItemsControl control = ItemsControl.ItemsControlFromItemContainer(container);

        return (0 == (control.Items.IndexOf(item) % 2)) ? EvenStyle : OddStyle;
    }
}

Defining the Styles

Now we must write styles that are specific to the container type to which the styles are to be applied. This means that for a ListBox, we are targeting its container type, ListBoxItem.

<Style x:Key="ListBoxItemEvenStyle" TargetType="ListBoxItem">
  <Setter Property="Background" Value="White"/>
  <Setter Property="BorderBrush" Value="LightGray"/>
  <Setter Property="BorderThickness" Value="0.5"/>
  <Setter Property="HorizontalContentAlignment" Value="Stretch"/>
</Style>

<Style x:Key="ListBoxItemOddStyle" TargetType="ListBoxItem" BasedOn="{StaticResource ListBoxItemEvenStyle}">
  <Setter Property="Background" Value="LightCyan"/>
</Style>

Note that I based the odd style on the even style. I recommend this always for minimizing duplicated style properties, because then in the odd style you need only override the properties you wish to differ from the even style.

Putting It Together

Now we need only assemble the previous two pieces.

<ItemsControlAlternatingStyleSelector
  x:Key="ListBoxItemAlternatingStyleSelector" 
  EvenStyle="{StaticResource ListBoxItemEvenStyle}"
  OddStyle="{StaticResource ListBoxItemOddStyle}"
/>

Once we've done this, we can apply the style selector to any ListBox.

<ListBox ItemContainerStyleSelector="{StaticResource ListBoxItemAlternatingStyleSelector}">
  ...
</ListBox>

That's it! Alternating row styles for a ListBox! In the same fashion, you could create styles for ListViewItem and apply them to a ListView with another ItemsControlAlternatingStyleSelector instance.

Code Listing

You can download the full code solution here.

3 comments

Comment from: Anon [Visitor]
I believe that AlternationCount is the intended way to do this - but thanks to this article for giving me the link that eventually helped me find this :)

see: http://msdn.microsoft.com/en-us/library/system.windows.controls.itemscontrol.alternationcount.aspx
03/02/09 @ 07:47
Comment from: Craig Gilchrist [Visitor] · http://www.gotfocussolutions.com/
Excellent article. Thanks for this!

I've spent a little bit of time struggling to style a listbox bound to an observable collection of items based on an enum value of each of the items. Your article meant that I quickly produced a StyleSelector and which returned one of the property styles based on the item enum value.

Craig
06/02/09 @ 08:35
Comment from: Michael Petter [Member] Email
To Anon,

Yes you are correct in using the AlternationCount in .NET 3.5 for simple alternation of styles based on index. I had already posted this in a follow-up article.

However, in .NET 3.0 or when requiring a more complex algorithm as in Craig's case, this is the way to go.

-Michael
06/02/09 @ 16:11

This post has 366 feedbacks awaiting moderation...

Leave a comment


Your email address will not be revealed on this site.

Your URL will be displayed.
(Line breaks become <br />)
(Name, email & website)
(Allow users to contact you through a message form (your email will not be revealed.)
May 2012
Sun Mon Tue Wed Thu Fri Sat
 << <   > >>
    1 2 3 4 5
6 7 8 9 10 11 12
13 14 15 16 17 18 19
20 21 22 23 24 25 26
27 28 29 30 31    

Development miscellany of interest. To some people. Or maybe just one person. Or maybe nobody.

Search

XML Feeds

powered by b2evolution