Regarding your requirements, I assume from the example you provided that:
- There are multiple rows.
- Each row has the same number of items (circles, here 5).
- All items (circles) have the same size.
This way, you can achieve the desired behavior with built-in functionality in a few steps.
- Change the
ItemsPanel
in the inner ListBox
to display the items (circles) horizontally (as a row)
- Set an
AlternationCount
of 2
to the outer ListBox
, so there are two alternation indices.
- Create an item container style for the out
ListBox
, which sets a Padding
(or Margin
if you want) of half the width of your circle items on the left for AlternationIndex
0
and the same on the right otherwise. You can create an instance of the already existing AlternationConverter
to define the Padding
s.
In this example, the paddings are fixed size (for me circle have a size of 50
, so the padding is 25
). You could also create a custom value converter to make this more dynamic, binding the real Size
.
<ListBox
Name="OuterListBox"
AlternationCount="2"
HorizontalAlignment="Center"
VerticalAlignment="Center"
Background="White"
BorderThickness="0"
ItemsSource="{Binding Board}">
<ListBox.ItemContainerStyle>
<Style TargetType="{x:Type ListBoxItem}" BasedOn="{StaticResource {x:Type ListBoxItem}}">
<Style.Resources>
<AlternationConverter x:Key="AlternationPaddingConverter">
<Thickness Right="25"/>
<Thickness Left="25"/>
</AlternationConverter>
</Style.Resources>
<Setter Property="Padding" Value="{Binding (ItemsControl.AlternationIndex), RelativeSource={RelativeSource Self}, Converter={StaticResource AlternationPaddingConverter}}"/>
</Style>
</ListBox.ItemContainerStyle>
<ListBox.ItemTemplate>
<DataTemplate>
<Grid>
<ListBox
Name="InnerListBox"
Background="Transparent"
BorderThickness="0"
ItemContainerStyle="{StaticResource ChangeListViewItemHighlight}"
ItemsSource="{Binding}"
PreviewKeyDown="InnerListBox_PreviewKeyDown">
<ListBox.ItemsPanel>
<ItemsPanelTemplate>
<VirtualizingStackPanel Orientation="Horizontal"/>
</ItemsPanelTemplate>
</ListBox.ItemsPanel>
<ListBox.ItemTemplate>
<DataTemplate>
<Ellipse
Width="{Binding Size}"
Height="{Binding Size}"
Cursor="Hand"
Fill="{Binding Background}" />
</DataTemplate>
</ListBox.ItemTemplate>
</ListBox>
</Grid>
</DataTemplate>
</ListBox.ItemTemplate>
</ListBox>

Additional question: how can I remove the highlight of the selected line?
In this simple case, you could use an ItemsControl
as outer control instead of a ListBox
. It has no selection. However, you have to style the ContentPresenter
and use Margin
then.
<ItemsControl
Name="OuterListBox"
AlternationCount="2"
HorizontalAlignment="Center"
VerticalAlignment="Center"
Background="White"
BorderThickness="0"
ItemsSource="{Binding Board}">
<ItemsControl.ItemContainerStyle>
<Style TargetType="{x:Type ContentPresenter}">
<Style.Resources>
<AlternationConverter x:Key="AlternationPaddingConverter">
<Thickness Right="25"/>
<Thickness Left="25"/>
</AlternationConverter>
</Style.Resources>
<Setter Property="Margin" Value="{Binding (ItemsControl.AlternationIndex), RelativeSource={RelativeSource Self}, Converter={StaticResource AlternationPaddingConverter}}"/>
</Style>
</ItemsControl.ItemContainerStyle>
<ItemsControl.ItemTemplate>
<DataTemplate>
<Grid>
<ListBox
Name="InnerListBox"
Background="Transparent"
BorderThickness="0"
ItemContainerStyle="{StaticResource ChangeListViewItemHighlight}"
ItemsSource="{Binding}"
PreviewKeyDown="InnerListBox_PreviewKeyDown">
<ListBox.ItemsPanel>
<ItemsPanelTemplate>
<VirtualizingStackPanel Orientation="Horizontal"/>
</ItemsPanelTemplate>
</ListBox.ItemsPanel>
<ListBox.ItemTemplate>
<DataTemplate>
<Ellipse
Width="{Binding Size}"
Height="{Binding Size}"
Cursor="Hand"
Fill="{Binding Background}" />
</DataTemplate>
</ListBox.ItemTemplate>
</ListBox>
</Grid>
</DataTemplate>
</ItemsControl.ItemTemplate>
</ItemsControl>