wpfxamllistviewdata-bindinglistviewitem

ListViewItem MultiDataTrigger and AlternationIndex


So I tried to apply a different Background color to each ListViewItem:

<Style.Triggers>
    <MultiDataTrigger>
        <MultiDataTrigger.Conditions>
            <Condition Binding="{Binding RelativeSource={RelativeSource Self}, Path=IsMouseOver}" Value="False"/>
            <Condition Binding="{Binding RelativeSource={RelativeSource Self}, Path=IsSelected}" Value="False"/>
            <Condition Binding="{Binding RelativeSource={RelativeSource Self}, Path=AlternationIndex}" Value="0"/>
        </MultiDataTrigger.Conditions>
        <Setter Property="Background" Value="Blue"/>
    </MultiDataTrigger>
    <MultiDataTrigger>
        <MultiDataTrigger.Conditions>
            <Condition Binding="{Binding RelativeSource={RelativeSource Self}, Path=IsMouseOver}" Value="False"/>
            <Condition Binding="{Binding RelativeSource={RelativeSource Self}, Path=IsSelected}" Value="False"/>
            <Condition Binding="{Binding RelativeSource={RelativeSource Self}, Path=AlternationIndex}" Value="1"/>
        </MultiDataTrigger.Conditions>
        <Setter Property="Background" Value="Red"/>
    </MultiDataTrigger>
</Style.Triggers>

But it seems that this does not affect my ListViewItems at all and all look the same.

Update

<Style x:Key="ListViewItemStyle" TargetType="{x:Type ListViewItem}">
    <Setter Property="SnapsToDevicePixels" Value="True"/>
    <Setter Property="VerticalAlignment" Value="Center"/>
    <Setter Property="FocusVisualStyle" Value="{x:Null}"/>
    <Setter Property="FontSize" Value="12"/>
    <Setter Property="Height" Value="40"/>
    <Setter Property="Cursor" Value="Hand"/>
    <Setter Property="Template">
        <Setter.Value>
            <ControlTemplate TargetType="{x:Type ListViewItem}">
                <Border BorderBrush="{TemplateBinding BorderBrush}" 
                        BorderThickness="{TemplateBinding BorderThickness}" 
                        Background="{TemplateBinding Background}" 
                        CornerRadius="2"
                        SnapsToDevicePixels="true">
                    <Border x:Name="InnerBorder"
                            BorderThickness="0"
                            CornerRadius="1">
                        <Grid>
                            <Grid.RowDefinitions>
                                <RowDefinition MaxHeight="11"/>
                                <RowDefinition/>
                            </Grid.RowDefinitions>
                            <GridViewRowPresenter Grid.RowSpan="2"
                                                  SnapsToDevicePixels="{TemplateBinding SnapsToDevicePixels}"
                                                  VerticalAlignment="{TemplateBinding VerticalContentAlignment}"/>
                        </Grid>
                    </Border>
                </Border>
            </ControlTemplate>
        </Setter.Value>
    </Setter>
    <Style.Triggers>

        <MultiDataTrigger>
            <MultiDataTrigger.Conditions>
                <Condition Binding="{Binding RelativeSource={RelativeSource Self}, Path=(ItemsControl.AlternationIndex)}" Value="0"/>
                <Condition Binding="{Binding RelativeSource={RelativeSource Self}, Path=IsMouseOver}" Value="False"/>
                <Condition Binding="{Binding RelativeSource={RelativeSource Self}, Path=IsSelected}" Value="False"/>
            </MultiDataTrigger.Conditions>
            <Setter Property="Background" Value="Blue"/>>
        </MultiDataTrigger>
        <MultiDataTrigger>
            <MultiDataTrigger.Conditions>
                <Condition Binding="{Binding RelativeSource={RelativeSource Self}, Path=(ItemsControl.AlternationIndex)}" Value="1"/>
                <Condition Binding="{Binding RelativeSource={RelativeSource Self}, Path=IsMouseOver}" Value="False"/>
                <Condition Binding="{Binding RelativeSource={RelativeSource Self}, Path=IsSelected}" Value="False"/>
            </MultiDataTrigger.Conditions>
            <Setter Property="Background" Value="Red"/>
        </MultiDataTrigger>
    </Style.Triggers>
</Style>

Solution

  • If you only use properties (or attached properties) of ListBoxItem in your conditions, you can simplify your style by using a MultiTrigger instead of a MultDataTrigger.

    <Style.Triggers>
       <MultiTrigger>
          <MultiTrigger.Conditions>
             <Condition Property="IsMouseOver" Value="False"/>
             <Condition Property="IsSelected" Value="False"/>
             <Condition Property="ItemsControl.AlternationIndex" Value="0"/>
          </MultiTrigger.Conditions>
          <Setter Property="Background" Value="Blue"/>
       </MultiTrigger>
       <MultiTrigger>
          <MultiTrigger.Conditions>
             <Condition Property="IsMouseOver" Value="False"/>
             <Condition Property="IsSelected" Value="False"/>
             <Condition Property="ItemsControl.AlternationIndex" Value="1"/>
          </MultiTrigger.Conditions>
          <Setter Property="Background" Value="Red"/>
       </MultiTrigger>
    </Style.Triggers>
    

    Otherwise, use the attached property binding syntax with parentheses for AlternationIndex, which is an attached property of ItemsControl, fully qualify it: (ItemsControl.AlternationIndex).

    <Style.Triggers>
       <MultiDataTrigger>
          <MultiDataTrigger.Conditions>
             <Condition Binding="{Binding RelativeSource={RelativeSource Self}, Path=IsMouseOver}" Value="False"/>
             <Condition Binding="{Binding RelativeSource={RelativeSource Self}, Path=IsSelected}" Value="False"/>
             <Condition Binding="{Binding RelativeSource={RelativeSource Self}, Path=(ItemsControl.AlternationIndex)}" Value="0"/>
          </MultiDataTrigger.Conditions>
          <Setter Property="Background" Value="Blue"/>
       </MultiDataTrigger>
       <MultiDataTrigger>
          <MultiDataTrigger.Conditions>
             <Condition Binding="{Binding RelativeSource={RelativeSource Self}, Path=IsMouseOver}" Value="False"/>
             <Condition Binding="{Binding RelativeSource={RelativeSource Self}, Path=IsSelected}" Value="False"/>
             <Condition Binding="{Binding RelativeSource={RelativeSource Self}, Path=(ItemsControl.AlternationIndex)}" Value="1"/>
          </MultiDataTrigger.Conditions>
          <Setter Property="Background" Value="Red"/>
       </MultiDataTrigger>
    </Style.Triggers>
    

    From the documentation on binding syntax for attached properties:

    To bind to an attached property, place parentheses around the attached property. For example, to bind to the attached property DockPanel.Dock, the syntax is Path=(DockPanel.Dock).


    Update for your comments and update: You have to set the AlternationCount property on your ListView to the number of alternations explicitly - in you case two - otherwise the default value will be used, which is zero. If the alternation count is zero, the alternation index will also be zero for all items, see Remarks in the documentation.