42

How do I get alternating colors on a ItemsControl? I have AlternationCount set to 2, but the ItemsControl.AlternationIndex property always returns 0.

        <ItemsControl ItemsSource="{Binding}" AlternationCount="2">
            <ItemsControl.Resources>
                <Style x:Key="FooBar" TargetType="Grid">
                    <Style.Triggers>
                        <Trigger Property="ItemsControl.AlternationIndex" Value="0">
                            <Setter Property="Background" Value="Blue"/>
                        </Trigger>
                        <Trigger Property="ItemsControl.AlternationIndex" Value="1">
                            <Setter Property="Background" Value="Red"/>
                        </Trigger>
                    </Style.Triggers>
                </Style>
            </ItemsControl.Resources>
            <ItemsControl.ItemTemplate>
                <DataTemplate>
                    <Grid Margin="0,0,0,10" Style="{StaticResource FooBar}">
                        <Grid.ColumnDefinitions>
                            <ColumnDefinition Width="25" />
                            <ColumnDefinition Width="100" />
                            <ColumnDefinition Width="100" />
                            <ColumnDefinition Width="100" />
                            <ColumnDefinition Width="100" />
                            <ColumnDefinition Width="100" />
                            <ColumnDefinition Width="100" />
                            <ColumnDefinition Width="*" />
                        </Grid.ColumnDefinitions>
                        <Grid.RowDefinitions >
                            <RowDefinition Height="Auto" />
                            <!--<RowDefinition Height="Auto" />-->
                        </Grid.RowDefinitions>

                        <CheckBox IsChecked="{Binding Checked, UpdateSourceTrigger=PropertyChanged}" VerticalAlignment="Center" />
                        <Label Grid.Column="1" Content="{Binding CompanyName}" />
                        <Label Grid.Column="2" Content="{Binding TradeKey}" />
                        <Label Grid.Column="3" Content="{Binding TradeDate}" ContentStringFormat="d" />
                        <Label Grid.Column="4" Content="{Binding Cusip}" />
                        <Label Grid.Column="5" Content="{Binding IssueName}" />
                        <Label Grid.Column="6" Content="{Binding TotalUnits}" ContentStringFormat="N0" />

                        <!--<Expander Grid.Row="0" Grid.Column="7" Grid.ColumnSpan="7" IsExpanded="True">
                            <Expander.Header>
                                <StackPanel Orientation="Horizontal">
                                    <Label Content="Allocations"/>
                                    <Button Content="Edit" Name="cmdEdit" Click="cmdEdit_Click"  />
                                </StackPanel>
                            </Expander.Header>-->
                        <DataGrid Grid.Column="7" IsReadOnly="True" ItemsSource="{Binding Territories}" AutoGenerateColumns="False" CanUserAddRows="False" CanUserDeleteRows="False">
                            <DataGrid.Columns>
                                <DataGridTextColumn Header="Rep on Ticket" Binding="{Binding TradeCustomer.RepNameNotes}" />
                                <DataGridTextColumn Header="Rep # on Ticket" Binding="{Binding TradeCustomer.RepNumberNotes}" />
                                <DataGridTextColumn Header="State" Binding="{Binding TradeCustomer.AccountStateKey}" />
                                <DataGridTextColumn Header="Qty. on Ticket" Binding="{Binding TradeCustomer.Quantity, StringFormat=N0}" />

                                <DataGridTextColumn Header="Zip Code" Binding="{Binding ZipCode}" />
                                <DataGridTextColumn Header="State" Binding="{Binding State}" />
                                <DataGridTextColumn Header="Territory" Binding="{Binding Territory}" />

                            </DataGrid.Columns>

                        </DataGrid>
                        <!--</Expander>-->

                    </Grid>
                </DataTemplate>
            </ItemsControl.ItemTemplate>
            <ItemsControl.ItemsPanel>
                <ItemsPanelTemplate>
                    <VirtualizingStackPanel />
                </ItemsPanelTemplate>
            </ItemsControl.ItemsPanel>
            <ItemsControl.Template>
                <ControlTemplate>
                    <Border BorderThickness="{TemplateBinding Border.BorderThickness}" Padding="{TemplateBinding Control.Padding}" BorderBrush="{TemplateBinding Border.BorderBrush}" Background="{TemplateBinding Panel.Background}" SnapsToDevicePixels="True">
                        <ScrollViewer Padding="{TemplateBinding Control.Padding}" Focusable="False">
                            <ItemsPresenter SnapsToDevicePixels="{TemplateBinding UIElement.SnapsToDevicePixels}" />
                        </ScrollViewer>
                    </Border>
                </ControlTemplate>
            </ItemsControl.Template>
        </ItemsControl>
Dave Clemmer
  • 3,741
  • 12
  • 49
  • 72
Jonathan Allen
  • 68,373
  • 70
  • 259
  • 447
  • Check my answer on https://stackoverflow.com/questions/3567778/how-to-use-alternationindex-in-itemscontrols/47231505#47231505 – Sean Nov 10 '17 at 21:39

3 Answers3

81

Check here http://www.codeproject.com/Articles/35886/WPF-ItemsControl-with-alternating-items-and-hover-.aspx

You have to change your code like this to get it working

    <ItemsControl ItemsSource="{Binding DataList}" AlternationCount="2">
        <ItemsControl.ItemTemplate>
            <DataTemplate>
                <Grid x:Name="FooBar" Margin="0,0,0,10">                    
                   ----------------------------
                   ----------------------------
                </Grid>
                <DataTemplate.Triggers>
                    <Trigger Property="ItemsControl.AlternationIndex" Value="0">
                        <Setter Property="Background" Value="Blue" TargetName="FooBar"/>
                    </Trigger>
                    <Trigger Property="ItemsControl.AlternationIndex" Value="1">
                        <Setter Property="Background" Value="Red" TargetName="FooBar"/>
                    </Trigger>
                </DataTemplate.Triggers>
            </DataTemplate>
        </ItemsControl.ItemTemplate>
biju
  • 17,554
  • 10
  • 59
  • 95
  • Ah, I see the difference now. Thanks. – Jonathan Allen Dec 13 '10 at 08:43
  • 8
    Just wanted to call out for this to work the `ItemsControl.AlternationCount` must also be set to `2` -- tripped me up for a few minutes – Aaron Hoffman Feb 15 '17 at 00:04
  • At first this did not work for me, but then I spotted the use of the Property AlternationCount which of course must be set to an integer above one to see any alternation at all. Thanks biju for this great sample. – Tore Aurstad Sep 19 '19 at 23:16
  • If you want to use this for a `TreeView` you need to copy the Triggers into `TreeView.ItemContainerStyle`. Otherwise it didn't work for me. – Stan1k May 19 '21 at 11:53
10

Here is an alternative which may be a bit more general

<DataTemplate x:Key="AlternatingTemplate">
    <Border>
        <Border.Style>
            <Style TargetType="{x:Type Border}">
                <Style.Triggers>
                    <DataTrigger Binding="{Binding Path=(ItemsControl.AlternationIndex), 
                                                   RelativeSource={RelativeSource AncestorType={x:Type ContentPresenter}}}" 
                                 Value="0">
                        <Setter Property="Background" Value="White" />
                    </DataTrigger>
                    <DataTrigger Binding="{Binding Path=(ItemsControl.AlternationIndex), 
                                                   RelativeSource={RelativeSource AncestorType={x:Type ContentPresenter}}}" 
                                 Value="1">
                        <Setter Property="Background" Value="LightGray" />
                    </DataTrigger>
                </Style.Triggers>
            </Style>
        </Border.Style>
        <ContentPresenter Content="{Binding}" />
    </Border>
</DataTemplate>

Usage:

<ItemsControl AlternationCount="2" 
              ItemTemplate="{StaticResource AlternatingTemplate}" 
              ItemsSource="{Binding SourceOfData}" />
Erik W
  • 179
  • 1
  • 9
1

If you don't want to use the DataTemplate approach, you can create a custom control that uses a ContentControl as the item container, therefore allowing you to specify a background color.

Class:

public class ItemsControlAlternating : ItemsControl
{
    static ItemsControlAlternating()
    {
        DefaultStyleKeyProperty.OverrideMetadata(typeof(ItemsControlAlternating),
                 new FrameworkPropertyMetadata(typeof(ItemsControlAlternating)));
    }

    protected override DependencyObject GetContainerForItemOverride()
    {
        return new ContentControl();
    }

    protected override bool IsItemItsOwnContainerOverride(object item)
    {
        return item is ContentControl;
    }
}

Resource Dictionary:

<Style TargetType="{x:Type c:ItemsControlAlternating}">
   <Setter Property="AlternationCount" Value="2"/>
   <Setter Property="Template">
       <Setter.Value>
           <ControlTemplate TargetType="{x:Type c:ItemsControlAlternating}">
               <ItemsPresenter/>
           </ControlTemplate>
       </Setter.Value>
   </Setter>
   <Setter Property="ItemContainerStyle">
       <Setter.Value>
           <Style TargetType="{x:Type ContentControl}">
               <Setter Property="Template">
                   <Setter.Value>
                       <ControlTemplate TargetType="{x:Type ContentControl}">
                           <Border Background="{TemplateBinding Background}">
                               <ContentPresenter/>
                           </Border>
                       </ControlTemplate>
                   </Setter.Value>
               </Setter>
               <Style.Triggers>
                   <Trigger Property="ItemsControl.AlternationIndex" Value="0">
                       <Setter Property="Background" Value="Gray"/>
                   </Trigger>
                   <Trigger Property="ItemsControl.AlternationIndex" Value="1">
                       <Setter Property="Background" Value="White"/>
                   </Trigger>
               </Style.Triggers>
           </Style>
       </Setter.Value>
   </Setter>
</Style>
Matt Jacobi
  • 864
  • 7
  • 17