Question

I have an ObservableCollection of BitmapSources and I want to display them all in a grid and override the selected and not selected styles. I have been looking at a lot of different ways to do this but have not managed to get it working to my satisfaction. My latest attempt looks something like this:

<ListBox ItemsSource={Binding Images}>
    <ListBox.ItemsPanel>
        <ItemsPanelTemplate>
            <WrapPanel ItemsHost="True">
        </ItemsPanelTemplate>
    </ListBox.ItemsPanel>
    <ListBox.ItemTemplate>
        <DataTemplate>
            <Border BorderBrush="Black" BorderThickness="3">
                <Image Source={Binding}>
            </Border>
        </DataTemplate>
    </ListBox.ItemTemplate>
</ListBox>

This does display the images, but the WrapPanel is always just one row... I don't want to have to scroll horizontally, so I want it to make row breaks by itself or be able to tell it that it should only have 3 items per row or something like that. Without the WrapPanel the images take one row each. Also, I don't really understand how to override the style for selected items and such since the DataTemplate's DataType is BitmapSource now, not ListBoxItem...

I have also tried a DataGrid (which seems more appropriate) with similar results.

How do I do this?

Was it helpful?

Solution

Define UniformGrid as your ItemsPanel and set the Columns value to the number of items you want to have per row.

          <ListBox.ItemsPanel>
                <ItemsPanelTemplate>
                    <UniformGrid Columns="3"/>
                </ItemsPanelTemplate>
            </ListBox.ItemsPanel>

And your style to override default selection background and border brush setting:

           <ListBox.ItemContainerStyle>
                <Style TargetType="ListBoxItem">
                    <Style.Resources>
                        <SolidColorBrush x:Key="{x:Static SystemColors.HighlightBrushKey}"
                         Color="Transparent"/>
                    </Style.Resources>
                    <Setter Property="BorderThickness" Value="0.5"/>
                    <Style.Triggers>
                        <Trigger Property="IsMouseOver" Value="True">
                            <Setter Property="BorderBrush" Value="blue"/>
                        </Trigger>
                        <Trigger Property="IsSelected" Value="True">
                            <Setter Property="BorderBrush" Value="Red"/>
                        </Trigger>
                    </Style.Triggers>

                </Style>

            </ListBox.ItemContainerStyle>

OTHER TIPS

You could simply disable horizontal scrolling. This will make the WrapPanel wrap its children.

<ListBox ItemsSource="{Binding Images}"
         ScrollViewer.HorizontalScrollBarVisibility="Disabled">
    <ListBox.ItemsPanel>
        <ItemsPanelTemplate>
            <WrapPanel/>
        </ItemsPanelTemplate>
    </ListBox.ItemsPanel>
    <ListBox.ItemTemplate>
        <DataTemplate>
            <Border BorderBrush="Black" BorderThickness="3">
                <Image Stretch="None" Source="{Binding}"/>
            </Border>
        </DataTemplate>
    </ListBox.ItemTemplate>
</ListBox>

-Edit-
The part about listbox width in this answer is not correct, see clemens answer instead

-Original post-
You need to constrict the width of the list box, either by setting the width or with some other parent layout. Otherwise the wrap panel will claim all the available width to put everything on one row. This happens to me alot when using scrollpanes for example

One tip is to setting different background colors to elements to see who is actually grabbing the space

You can change the selected styles by setting the ItemsContainerStyle

Licensed under: CC-BY-SA with attribution
Not affiliated with StackOverflow
scroll top