How to use AlternationIndex in ItemsControls?

Viewed 29962

I have seen some articles that show how to use AlternationIndex with ListBoxes or ListViews, but I had spent a few hours trying to get alternating background colors on the base ItemsControl class and nothing seems to work. All ListBox samples I saw use ListBoxItem as the target type for the style that sets the background based onAlternationIndex - like this one from MSDN:

<Grid>
    <Grid.Resources>
        <Style x:Key="alternatingWithTriggers" TargetType="{x:Type ListBoxItem}">
            <Setter Property="Background" Value="Blue"/>
            <Setter Property="Foreground" Value="White"/>
            <Style.Triggers>
                <Trigger Property="ListBox.AlternationIndex" Value="1">
                    <Setter Property="Background" Value="CornflowerBlue"/>
                    <Setter Property="Foreground" Value="Black"/>
                </Trigger>
                <Trigger Property="ListBox.AlternationIndex" Value="2">
                    <Setter Property="Background" Value="LightBlue"/>
                    <Setter Property="Foreground" Value="Navy"/>
                </Trigger>
            </Style.Triggers>
        </Style>

    </Grid.Resources>
    <ListBox AlternationCount="3" ItemsSource="{StaticResource data}" 
             ItemContainerStyle="{StaticResource alternatingWithTriggers}">
    </ListBox>
</Grid>

I want to use the ItemsControl because I do not want the selection functionality and I think restyling a ListBox to hide it might not be the best choice.

This is one of the things I was trying:

<DataTemplate DataType="{x:Type vm:ObservableCollectionItem}">
    <Grid>
        <!-- some content here -->
    </Grid>
</DataTemplate>

<!-- ... -->

<ItemsControl
    ItemsSource="{Binding ObservableCollectionItems}"
    AlternationCount="2"
>
    <ItemsControl.ItemContainerStyle>
        <Style>
            <Style.Triggers>
                <Trigger Property="ItemsControl.AlternationIndex" Value="0">
                    <Setter Property="Grid.Background" Value="Red"></Setter>
                </Trigger>
                <Trigger Property="ItemsControl.AlternationIndex" Value="1">
                    <Setter Property="Grid.Background" Value="Blue"></Setter>
                </Trigger>
            </Style.Triggers>
        </Style>
    </ItemsControl.ItemContainerStyle>
</ItemsControl>

The problem I saw was that the visual tree has a list of ContentPresenters that have ItemsControl.AlternationIndex alternate between 0 and 1, but the Grid in each ContentPresenter has ItemsControl.AlternationIndex set to 0.

There is probably something obvious I am missing...

5 Answers

Or, as I found on another post, and it works great for me... You can simply use a binding...

{Binding
    RelativeSource={RelativeSource Mode=TemplatedParent}, 
    Path=(ItemsControl.AlternationIndex)}

NB: remember to add AlterationCount="100" on your ItemsControl

I don't know how any of the prior answers are legit. I couldn't make any of them work (didn't try Jacobi's though). Anyways, I found the path to enlightenment here: http://www.dotnetcurry.com/wpf/1211/wpf-items-control-advanced-topic, which lead me to adding the following in the xaml.cs code-behind:

public sealed class CustomItemsControl : ItemsControl
{
    protected override DependencyObject GetContainerForItemOverride()
    {
        return new ContentControl();
    }
}

and this in the xaml itself

    <local:CustomItemsControl AlternationCount="2" 
          ItemsSource="{Binding Cells, Mode=OneWay}">
        <local:CustomItemsControl.ItemContainerStyle>
            <Style TargetType="ContentControl">
                <Setter Property="Template">
                    <Setter.Value>
                        <ControlTemplate TargetType="ContentControl">
                            <Border Background="{TemplateBinding Background}">
                                <ContentPresenter/>
                            </Border>
                        </ControlTemplate>
                    </Setter.Value>
                </Setter>

                <Style.Triggers>
                    <Trigger Property="ItemsControl.AlternationIndex" Value="0">
                        <Setter Property="Background" Value="WhiteSmoke"/>
                    </Trigger>
                    <Trigger Property="ItemsControl.AlternationIndex" Value="1">
                        <Setter Property="Background" Value="LightGray"/>
                    </Trigger>
                </Style.Triggers>
            </Style>
        </local:CustomItemsControl.ItemContainerStyle>
    </local:CustomItemsControl>

This was so damn hard to find a working solution to that I'm actually angry

Related