Here you can do this in code using a ListBox with a UniformGrid as ItemsPanelTemplate . In addition, you can only use UniformGrid and place it inside a ScrollViewer , but since the ListBox already handles the selection and all that, you probably stick to it better. This code will automatically adjust the number of elements per line depending on the available width.
MoviePresenter.cs:
public class MoviePresenter : ListBox { public MoviePresenter() { FrameworkElementFactory factory = new FrameworkElementFactory(typeof(UniformGrid)); factory.SetBinding( UniformGrid.ColumnsProperty, new Binding(nameof(ActualWidth)) { Source = this, Mode = BindingMode.OneWay, Converter = new WidthToColumnsConverter() { ItemMinWidth = 100 } }); ItemsPanel = new ItemsPanelTemplate() { VisualTree = factory }; } } internal class WidthToColumnsConverter : IValueConverter { public double ItemMinWidth { get; set; } = 1; public object Convert(object value, Type targetType, object parameter, CultureInfo culture) { double? actualWidth = value as double?; if (!actualWidth.HasValue) return Binding.DoNothing; return Math.Max(1, Math.Floor(actualWidth.Value / ItemMinWidth)); } public object ConvertBack(object value, Type targetType, object parameter, CultureInfo culture) { throw new NotImplementedException(); } }
MovieItem.cs:
public class MovieItem : Grid { public MovieItem() { RowDefinitions.Add(new RowDefinition() { Height = GridLength.Auto }); RowDefinitions.Add(new RowDefinition() { Height = GridLength.Auto }); RowDefinitions.Add(new RowDefinition() { Height = GridLength.Auto }); RowDefinitions.Add(new RowDefinition() { Height = GridLength.Auto }); Image image = new Image(); image.Stretch = Stretch.UniformToFill; image.SetBinding(Image.SourceProperty, new Binding(nameof(ImageSource)) { Source = this }); Children.Add(image); TextBlock title = new TextBlock(); title.FontSize += 1; title.FontWeight = FontWeights.Bold; title.Foreground = Brushes.Beige; title.TextTrimming = TextTrimming.CharacterEllipsis; title.SetBinding(TextBlock.TextProperty, new Binding(nameof(Title)) { Source = this }); Grid.SetRow(title, 1); Children.Add(title); TextBlock year = new TextBlock(); year.Foreground = Brushes.LightGray; year.TextTrimming = TextTrimming.CharacterEllipsis; year.SetBinding(TextBlock.TextProperty, new Binding(nameof(Year)) { Source = this }); Grid.SetRow(year, 2); Children.Add(year); TextBlock releaseDate = new TextBlock(); releaseDate.Foreground = Brushes.LightGray; releaseDate.TextTrimming = TextTrimming.CharacterEllipsis; releaseDate.SetBinding(TextBlock.TextProperty, new Binding(nameof(ReleaseDate)) { Source = this }); Grid.SetRow(releaseDate, 3); Children.Add(releaseDate); } public static readonly DependencyProperty ImageSourceProperty = DependencyProperty.Register("ImageSource", typeof(string), typeof(MovieItem), new PropertyMetadata(null)); public static readonly DependencyProperty TitleProperty = DependencyProperty.Register("Title", typeof(string), typeof(MovieItem), new PropertyMetadata(null)); public static readonly DependencyProperty YearProperty = DependencyProperty.Register("Year", typeof(string), typeof(MovieItem), new PropertyMetadata(null)); public static readonly DependencyProperty ReleaseDateProperty = DependencyProperty.Register("ReleaseDate", typeof(string), typeof(MovieItem), new PropertyMetadata(null)); public string ImageSource { get { return (string)GetValue(ImageSourceProperty); } set { SetValue(ImageSourceProperty, value); } } public string Title { get { return (string)GetValue(TitleProperty); } set { SetValue(TitleProperty, value); } } public string Year { get { return (string)GetValue(YearProperty); } set { SetValue(YearProperty, value); } } public string ReleaseDate { get { return (string)GetValue(ReleaseDateProperty); } set { SetValue(ReleaseDateProperty, value); } } }
MainWindow.xaml:
<Grid> <local:MoviePresenter x:Name="moviePresenter" ScrollViewer.HorizontalScrollBarVisibility="Disabled"/> </Grid>
MainWindow.xaml.cs
public partial class MainWindow : Window { public MainWindow() { InitializeComponent(); for (int i = 0; i < 20; i++) { DateTime dummyDate = DateTime.Now.AddMonths(-i).AddDays(-(i * i)); MovieItem item = new MovieItem() { ImageSource = $"http://fakeimg.pl/100x200/?text=Image_{i}", Title = $"Dummy movie {i}", Year = $"{dummyDate.Year}", ReleaseDate = $"{dummyDate.ToLongDateString()}" }; moviePresenter.Items.Add(item); } } }