◆ AlternationIndex/AlternationCount
◆ N が変化するなら MultiBinding で 2 つの値が一緒なら True 返す Converter を通す 

ListBox で何番目かの要素にスタイルをあてたいときがあります

N が固定のとき

何番目というのが固定なときは単純です

データはこういうの
private class BindingData
{
    public List<Item> items { get; set; } = new List<Item>
    {
        new Item { name = "fawebae" },
        new Item { name = "jnaikez" },
        new Item { name = "nniq2la" },
        new Item { name = "z9dkwol" },
        new Item { name = "hik1kdz" },
        new Item { name = "lpkm4ed" },
        new Item { name = "kiijwee" },
        new Item { name = "lpkm4ed" },
        new Item { name = "kkkoaoe" },
        new Item { name = "ddwafi1" },
    };
}

public class Item
{
    public string name { get; set; }
}

public MainWindow()
{
    this.DataContext = new BindingData();
}


XAML では ListBox に AlternationCount を設定しておき DataTrigger で AlternationIndex を参照します
<ListBox ItemsSource="{Binding items}" AlternationCount="999">
    <ItemsControl.ItemTemplate>
        <DataTemplate>
            <StackPanel Orientation="Horizontal">
                <StackPanel.Resources>
                    <Style TargetType="StackPanel">
                        <Style.Triggers>
                            <DataTrigger Binding="{Binding RelativeSource={RelativeSource AncestorType=ListBoxItem},Path=(ListBox.AlternationIndex)}" Value="3">
                                <Setter Property="Background" Value="LawnGreen"/>
                            </DataTrigger>
                        </Style.Triggers>
                    </Style>
                </StackPanel.Resources>
                <TextBlock Text="{Binding RelativeSource={RelativeSource AncestorType=ListBoxItem},Path=(ListBox.AlternationIndex),StringFormat={}{0}:}" />
                <TextBlock Text="{Binding name}"/>
            </StackPanel>
        </DataTemplate>
    </ItemsControl.ItemTemplate>
</ListBox>

wpfsmp02

AlternationIndex は要素のインデックスで 0 から順にひとつずつ増えていきます
AlternationCount の数ごとにリセットされるので AlternatonCount が 4 で要素が 10 あると 0,1,2,3,0,1,2,3,0,1 という AlternationIndex になります

AlternationCount に要素数より大きい数値を指定しておくと繰り返しが起きないので連番として使えます

ここでは 999 ですがちゃんとやるなら namespace にこれを指定しておいて
xmlns:s="clr-namespace:System;assembly=mscorlib"

int の最大値を指定すれば
AlternationCount="{x:Static s:Int32.MaxValue}"

安心して連番にできます
999 だと要素数ふえると困りますしね



AlternationCount を 4 にした場合の実行結果はこうなります
左側の数値が 3 の次に 0 になっていますね
wpfsmp03

偶数番目とかに使えます
(CSS の nth-type-of のほうが使いやすいです)


N が変化するとき

偶数番目などの使い方じゃなくて 選択中のものなど操作によってスタイル要素を変えたいときがあります
<ListBox ItemsSource="{Binding items}" AlternationCount="{x:Static s:Int32.MaxValue}">
    <ItemsControl.ItemTemplate>
        <DataTemplate>
            <StackPanel Orientation="Horizontal">
                <StackPanel.Resources>
                    <Style TargetType="StackPanel">
                        <Style.Triggers>
                            <DataTrigger Binding="{Binding RelativeSource={RelativeSource AncestorType=ListBoxItem},Path=(ListBox.AlternationIndex)}" Value="{Binding index}">
                                <Setter Property="Background" Value="LawnGreen"/>
                            </DataTrigger>
                        </Style.Triggers>
                    </Style>
                </StackPanel.Resources>
                <TextBlock Text="{Binding RelativeSource={RelativeSource AncestorType=ListBoxItem},Path=(ListBox.AlternationIndex),StringFormat={}{0}:}" />
                <TextBlock Text="{Binding name}"/>
            </StackPanel>
        </DataTemplate>
    </ItemsControl.ItemTemplate>
</ListBox>

Value のほうを変えたい要素の index に Binding すれば良さそうに思えます
ですが Value に対しては Binding ができないとエラーです

ちょっとめんどうですが MultiBinding と Converter を通して Binding プロパティの方に動的にかわる部分をまとめないといけないです

BindingData クラスに index プロパティを追加します
private class BindingData : NotifyHelper
{
    public List<Item> items { get; set; } = new List<Item>
    {
        new Item { name = "fawebae" },
        new Item { name = "jnaikez" },
        new Item { name = "nniq2la" },
        new Item { name = "z9dkwol" },
        new Item { name = "hik1kdz" },
        new Item { name = "lpkm4ed" },
        new Item { name = "kiijwee" },
        new Item { name = "lpkm4ed" },
        new Item { name = "kkkoaoe" },
        new Item { name = "ddwafi1" },
    };

    private int _index = 0;
    public int index
    {
        get { return this._index; }
        set
        {
            this._index = value;
            this.notify(nameof(index));
        }
    }

}

NotifyHelper はソースの変更通知するメソッドを使えるようにしているものです
特別なことはないので省略します


値が等しい場合に True を返すコンバータを作ります(用意されてそうなものだけど見当たらなかったです)
class AreEqualsConverter : IMultiValueConverter
{
    public object Convert(object[] values, Type targetType, object parameter, System.Globalization.CultureInfo culture)
    {
        if (values.Length < 2)
        {
            return false;
        }
        foreach (var item in values.Skip(1))
        {
            if (!values[0].Equals(item))
            {
                return false;
            }
        }
        return true;
    }
    public object[] ConvertBack(object value, Type[] targetType, object parameter, System.Globalization.CultureInfo culture)
    {
        throw new NotSupportedException();
    }
}

XAML の Trigger でこのコンバータを使います
<ListBox ItemsSource="{Binding items}" AlternationCount="{x:Static s:Int32.MaxValue}">
    <ItemsControl.ItemTemplate>
        <DataTemplate>
            <StackPanel Orientation="Horizontal">
                <StackPanel.Resources>
                    <local:AreEqualsConverter x:Key="equal_converter"/>
                    <Style TargetType="StackPanel">
                        <Style.Triggers>
                            <DataTrigger Value="True">
                                <DataTrigger.Binding>
                                    <MultiBinding Converter="{StaticResource equal_converter}">
                                        <Binding RelativeSource="{RelativeSource AncestorType=ListBoxItem}" Path="(ListBox.AlternationIndex)" />
                                        <Binding RelativeSource="{RelativeSource AncestorType=ListBox}" Path="DataContext.index" />
                                    </MultiBinding>
                                </DataTrigger.Binding>
                                <Setter Property="Background" Value="MistyRose"/>
                            </DataTrigger>

                        </Style.Triggers>
                    </Style>
                </StackPanel.Resources>
                <TextBlock Text="{Binding RelativeSource={RelativeSource AncestorType=ListBoxItem},Path=(ListBox.AlternationIndex),StringFormat={}{0}:}" />
                <TextBlock Text="{Binding name}"/>
            </StackPanel>
        </DataTemplate>
    </ItemsControl.ItemTemplate>
</ListBox>

こうすれば AlternationIndex と BindingData にある index が等しいときに True になり Trigger が実行されます

背景が全体になってない

今回のやりたいこととは関係ないですが このコードだと背景色が文字のところだけになっていて全体の背景色になっていません
ListBox だとマウスオーバーしたら水色の枠と背景でわかりやすく表示してくれますが それと同じように全体に背景色を設定してみます

<ListBox ItemsSource="{Binding items}" AlternationCount="{x:Static s:Int32.MaxValue}">
    <ListBox.Resources>
        <local:AreEqualsConverter x:Key="equal_converter"/>
        <Style TargetType="ListBoxItem">
            <Style.Triggers>
                <DataTrigger Value="True">
                    <DataTrigger.Binding>
                        <MultiBinding Converter="{StaticResource equal_converter}">
                            <Binding RelativeSource="{RelativeSource Self}" Path="(ListBox.AlternationIndex)" />
                            <Binding RelativeSource="{RelativeSource AncestorType=ListBox}" Path="DataContext.index" />
                        </MultiBinding>
                    </DataTrigger.Binding>
                    <Setter Property="Background" Value="MistyRose"/>
                </DataTrigger>
            </Style.Triggers>
        </Style>
    </ListBox.Resources>
    <ItemsControl.ItemTemplate>
        <DataTemplate>
            <StackPanel Orientation="Horizontal">
                <TextBlock Text="{Binding RelativeSource={RelativeSource AncestorType=ListBoxItem},Path=(ListBox.AlternationIndex),StringFormat={}{0}:}" />
                <TextBlock Text="{Binding name}"/>
            </StackPanel>
        </DataTemplate>
    </ItemsControl.ItemTemplate>
</ListBox>


ItemTemplate の中ではなく ListBox の Resources に ListBoxItem のスタイルとして設定すればいいです
RelativeSource で ListBoxItem だったところを Self にしないといけないです


wpfsmp04


わずかに背景色のほうが小さいのは Border がない分です




それにしても XAML もコールバック地獄なみに波動拳してますね(笑