Below code implements 1 and 2. The item in the middle of the horizontal listbox is always selected. The listbox need some styling to look good, like using Opacity to show which items are displayed and not.
XAML:
<Window x:Class="FlowListTest.Window1"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
Height="300" Width="300">
<ListBox
ItemsSource="{Binding Path=Items}"
ScrollViewer.HorizontalScrollBarVisibility="Auto"
ScrollViewer.ScrollChanged="OnScrollChanged"
SelectionChanged="OnSelectionChanged">
<ListBox.ItemsPanel>
<ItemsPanelTemplate>
<StackPanel Orientation="Horizontal" />
</ItemsPanelTemplate>
</ListBox.ItemsPanel>
<ListBox.ItemTemplate>
<DataTemplate>
<Border CornerRadius="10" BorderBrush="Red" BorderThickness="2">
<TextBlock Text="{Binding}" Margin="5" Width="20" Height="100"/>
</Border>
</DataTemplate>
</ListBox.ItemTemplate>
</ListBox>
</Window>
Code behind:
using System;
using System.Collections.Generic;
using System.Windows;
using System.Windows.Controls;
namespace FlowListTest
{
public partial class Window1 : Window
{
public Window1()
{
InitializeComponent();
DataContext = this;
}
public IEnumerable<string> Items
{
get
{
for (int i = 0; i < 100; i++)
{
yield return i.ToString();
}
}
}
private void OnSelectionChanged(object sender, SelectionChangedEventArgs e)
{
(sender as ListBox).SelectedIndex = _selectedIndex;
}
private void OnScrollChanged(object sender, ScrollChangedEventArgs e)
{
_selectedIndex = (int)(e.HorizontalOffset + Math.Truncate(e.ViewportWidth / 2));
(sender as ListBox).SelectedIndex = _selectedIndex;
}
private int _selectedIndex;
}
}