C# – Make ListBox size to fit the ItemsPanel used as its ItemsPresenter

ccustom-controlsgeneric.xamlwpfxaml

I have a custom control ListBox that I would like to adjust its size according to the size of its ItemsPanel. For the items panel, I have a custom control WrapPanel that arranges the items accordingly. As you can see in the screen shot, the ListBox prefers to size itself to its parent control or availableSize.

So then I tried to make a custom control Grid, that had an ItemsSource property that handed the items to its listbox. But that didn't work either. When the Grid would arrange, then the ListBox would Arrange, which would cause the Grid to Arrange and so on.

So my question is, how to I create a custom control that has an ItemsSource property and an ItemsPresenter that sizes itself according to the contents of its children??

Screenshot of ListBox Custom Control

Best Answer

You just have to set your ListBox HorizontalAlignment to Left, and VerticalAlignment to Top. This should do the trick.

Simple example :

MainWindow.xaml

<Window x:Class="ListBoxFitItemsPanel.MainWindow"
        xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
        xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
        Title="MainWindow" Height="400" Width="400">
    <ListBox ScrollViewer.HorizontalScrollBarVisibility="Disabled" ScrollViewer.VerticalScrollBarVisibility="Disabled" Background="Red" HorizontalAlignment="Left" VerticalAlignment="Top" >
        <ListBox.ItemsPanel>
            <ItemsPanelTemplate>
                <WrapPanel Background="AntiqueWhite" Margin="5" />
            </ItemsPanelTemplate>
        </ListBox.ItemsPanel>

        <Rectangle Width="100" Height="100" Fill="LightSlateGray" Stroke="Black" StrokeThickness="1" Margin="5" />
        <Rectangle Width="100" Height="100" Fill="LightSlateGray" Stroke="Black" StrokeThickness="1" Margin="5" />
        <Rectangle Width="100" Height="100" Fill="LightSlateGray" Stroke="Black" StrokeThickness="1" Margin="5" />
        <Rectangle Width="100" Height="100" Fill="LightSlateGray" Stroke="Black" StrokeThickness="1" Margin="5" />
        <Rectangle Width="100" Height="100" Fill="LightSlateGray" Stroke="Black" StrokeThickness="1" Margin="5" />
        <Rectangle Width="100" Height="100" Fill="LightSlateGray" Stroke="Black" StrokeThickness="1" Margin="5" />
        <Rectangle Width="100" Height="100" Fill="LightSlateGray" Stroke="Black" StrokeThickness="1" Margin="5" />
        <Rectangle Width="100" Height="100" Fill="LightSlateGray" Stroke="Black" StrokeThickness="1" Margin="5" />
        <Rectangle Width="100" Height="100" Fill="LightSlateGray" Stroke="Black" StrokeThickness="1" Margin="5" />
    </ListBox>
</Window>

enter image description here

EDIT : It also works in a Binding scenario :

MainWindow.xaml

<Window x:Class="ListBoxFitItemsPanel.MainWindow"
        xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
        xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
        xmlns:local="clr-namespace:ListBoxFitItemsPanel"
        Title="MainWindow" Height="400" Width="400">
    <Window.Resources>
        <DataTemplate DataType="{x:Type local:Item}">
            <Rectangle Width="100" Height="100" Fill="LightSlateGray" Stroke="Black" StrokeThickness="1" Margin="5" />
        </DataTemplate>
    </Window.Resources>
    <ListBox ItemsSource="{Binding Items}" ScrollViewer.HorizontalScrollBarVisibility="Disabled" ScrollViewer.VerticalScrollBarVisibility="Disabled" Background="Red" HorizontalAlignment="Left" VerticalAlignment="Top" >
        <ListBox.ItemsPanel>
            <ItemsPanelTemplate>
                <WrapPanel Background="AntiqueWhite" Margin="5" />
            </ItemsPanelTemplate>
        </ListBox.ItemsPanel>
    </ListBox>
</Window>

MainWindow.xaml.cs

using System.Collections.Generic;
using System.Windows;

namespace ListBoxFitItemsPanel
{
    /// <summary>
    /// Interaction logic for MainWindow.xaml
    /// </summary>
    public partial class MainWindow : Window
    {
        public MainWindow()
        {
            InitializeComponent();
            DataContext = this;
        }

        public IEnumerable<Item> Items
        {
            get
            {
                for (int i = 0; i < 9; i++)
                {
                    yield return new Item();
                }
            }
        }
    }

    public class Item { }
}
Related Topic