Create circular listview in wpf

In my little Wpf ListView with better touch support I had the need to support the concept of circular scrolling. What I want is the ability to scroll elements continuously, as if the list was circular; if I have 5 elements, from 0 to 4 I want to scroll left from the element 4 to the element 0.

As you can see in this short video the listview appears not to have an end and we can scroll how many elements we want. This is a trick or an illusion and is obtained with a  little support from the viewmodel. This KineticListView was bound to a peculiar property of the ViewModel


Property is called DataToShowSingleRepetition, and here is how it is handled in the ViewModel.

   1: DataToShowSingleRepetition.Add(new Data() { Value = "Stringa che è abbastanza lunga " + 0, IValue = 0 });
   2: DataToShowSingleRepetition.Add(new Data() { Value = "Stringa che è abbastanza lunga " + 1, IValue = 1 });
   3: DataToShowSingleRepetition.Add(new Data() { Value = "Stringa che è abbastanza lunga " + 2, IValue = 2 });
   4: DataToShowSingleRepetition.Add(new Data() { Value = "Stringa che è abbastanza lunga " + 3, IValue = 3 });
   5: DataToShowSingleRepetition.Add(new Data() { Value = "Stringa che è abbastanza lunga " + 4, IValue = 4 });
   7: var temp = DataToShowSingleRepetition.Last();
   8: DataToShowSingleRepetition.Add(DataToShowSingleRepetition.First());

   9: DataToShowSingleRepetition.Insert(0, temp);

The trick in the last three lines. We need to show five elements, but I place a copy of the last one (the one with value 4) at the beginning of the list and a copy of the first (the one with value 0) to the end of the list. This is needed to “simulate” the fact that we are actually scrolling a circular set of elements.

The logic behind this is: when the first logical element (the one with value 0) is shown, we should be able to scroll the list to the right, showing the last logical element (the one with value 4) to the left, and since the original ListView does not support this concept we need to repeat the logical last element as the first element. What it happens is that, when the KineticListView finish to scroll, it check if we are on the physical first element (the one with value 4). If it is true, it immediately moves to the same element at the end of the list.


In this example the list shows only one element but we can use the circular option even when the list shows multiple items, we need only to repeat more elements, here is the result.

As you can see the illusion to have circular elements is maintained even if we are actually showing three elements at a single time. Here is the code in the ViewModel.

   1: DataToShowRepetition.Insert(0, DataToShow[DataToShow.Count - 1]);

   2: DataToShowRepetition.Insert(0, DataToShow[DataToShow.Count - 2]);

   3: DataToShowRepetition.Insert(0, DataToShow[DataToShow.Count - 3]);

   4: DataToShowRepetition.Insert(0, DataToShow[DataToShow.Count - 4]);

   5: DataToShowRepetition.Insert(0, DataToShow[DataToShow.Count - 5]);

   6: DataToShowRepetition.Insert(0, DataToShow[DataToShow.Count - 6]);

   7: DataToShowRepetition.Add(DataToShow[0]);

   8: DataToShowRepetition.Add(DataToShow[1]);

   9: DataToShowRepetition.Add(DataToShow[2]);

  10: DataToShowRepetition.Add(DataToShow[3]);

  11: DataToShowRepetition.Add(DataToShow[4]);

  12: DataToShowRepetition.Add(DataToShow[5]);

We are actually repeating six element for each side of the list and KineticListView has a corresponding property used to specify how many elements we are repeating, called CircularRepetitions.

   1: <KineticListView:KineticListView 

   2:         x:Name="listView3" ItemsSource="{Binding Path=DataToShowRepetition}"

   3:           Width="600"

   4:           ItemTemplate="{DynamicResource DataTemplate1}" 

   5:           BorderThickness="0"

   6:           Circular="true"

   7:           CircularRepetitions="6"

   8:           Direction="Horizontal">

In the code of the kinetic there is some simple math to handle this situation that is really similar to the standard one with only one element.