1

I want to achieve something similar with this image:

Alternating rows.

Rows with alternating alignment - aligned to the left when the row's index is even, aligned to the right when the row's index is uneven.

I tried to use ListBox of ListBox, binding with ObservableCollection<ObservableCollection<Circle>>. Should I bind the Margin property of the second ListBox in order to achieve the alternating alignment?

<ListBox
  Name="OuterListBox"
  HorizontalAlignment="Center"
  VerticalAlignment="Center"
  Background="White"
  BorderThickness="0"
  ItemsSource="{Binding Board}">
  <ListBox.ItemTemplate>
    <DataTemplate>
      <Grid>
        <ListBox
          Name="InnerListBox"
          HorizontalAlignment="{Binding HorizontalAlignment}"
          Background="Transparent"
          BorderThickness="0"
          ItemContainerStyle="{StaticResource ChangeListViewItemHighlight}"
          ItemsSource="{Binding}"
          PreviewKeyDown="InnerListBox_PreviewKeyDown">
          <ListBox.ItemTemplate>
            <DataTemplate>
                <Ellipse
                  Width="{Binding Size}"
                  Height="{Binding Size}"
                  Cursor="Hand"
                  Fill="{Binding Background}" />
            </DataTemplate>
          </ListBox.ItemTemplate>
        </ListBox>
      </Grid>
    </DataTemplate>
  </ListBox.ItemTemplate>
</ListBox>
thatguy
  • 21,059
  • 6
  • 30
  • 40

1 Answers1

1

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 Paddings.

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>

Circle board with rows that have an alternating padding.


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>
thatguy
  • 21,059
  • 6
  • 30
  • 40