WPF ListBox that lays out its items horizontally - wpf

I'm trying to write a WPF application for displaying images from a selection.
I want to display all of the available images in a banner along the top of the window, and display the main selected image in the main window for further processing.
If I wanted the list on the Left of the window, displaying the images vertically, I can do this quite elegantly using databinding.
<ListBox
Name="m_listBox"
IsSynchronizedWithCurrentItem="True"
ItemsSource="{Binding}"
>
<ListBox.ItemTemplate>
<DataTemplate>
<Image Source="{Binding}" Width="60" Stretch="Uniform" />
</DataTemplate>
</ListBox.ItemTemplate>
</ListBox>
Is there a straightforward way I can make this horizontal instead of vertical?
The main requirements of a solution is:
The items are populated using databinding
The selected item is changed simply by the user clicking it.

WrapPanel
<ListBox ScrollViewer.HorizontalScrollBarVisibility="Disabled">
<ListBox.ItemsPanel>
<ItemsPanelTemplate>
<WrapPanel IsItemsHost="True" />
</ItemsPanelTemplate>
</ListBox.ItemsPanel>
<ListBoxItem>listbox item 1</ListBoxItem>
<ListBoxItem>listbox item 2</ListBoxItem>
<ListBoxItem>listbox item 3</ListBoxItem>
<ListBoxItem>listbox item 4</ListBoxItem>
<ListBoxItem>listbox item 5</ListBoxItem>
</ListBox>
WPF Tutorial

The default ItemsPanel for the ListBox control is a VirtualizingStackPanel, so if you want the normal, default experience for the control but just have it laid out horizontally, you should specify this (and change the orientation).
Example:
<ListBox>
<ListBox.ItemsPanel>
<ItemsPanelTemplate>
<VirtualizingStackPanel IsItemsHost="True" Orientation="Horizontal"/>
</ItemsPanelTemplate>
</ListBox.ItemsPanel>
</ListBox>

Here is example of StackPanel.
Horizontal Breadcrumb with Mvvm binding
<ItemsControl
x:Name="tStack"
Grid.Row="1"
Grid.Column="0"
Height="40"
Background="Red"
ItemsSource="{Binding BreadCrumbs}">
<ItemsControl.ItemsPanel>
<ItemsPanelTemplate>
<StackPanel Orientation="Horizontal" />
</ItemsPanelTemplate>
</ItemsControl.ItemsPanel>
<ItemsControl.ItemTemplate>
<DataTemplate>
<Button
Margin="5"
CommandParameter="{Binding .}"
Command="{Binding BreadcrumbClickCommand, RelativeSource={RelativeSource AncestorType=ItemsControl}, Path=DataContext.BreadcrumbClickCommand}"
Content="{Binding Name}" />
</DataTemplate>
</ItemsControl.ItemTemplate>
</ItemsControl>

Related

Scrolling of a listbox inside another listbox

I have a listbox (with normal vertical orientation), each element of which is a listbox with horizontal orientation.
I want to have a ScrollBar inside of internal listbox. So, my problem is how to set width of internal listbox according to real current width of external.
My current code is:
<Window.Resources>
<HierarchicalDataTemplate x:Key="ItemTemplateSchedule">
<ListBox>
<ListBox.ItemsPanel>
<ItemsPanelTemplate>
<StackPanel Orientation="Horizontal" />
</ItemsPanelTemplate>
</ListBox.ItemsPanel>
<ListBoxItem>My-Very-Long-Item-Nimber-1___</ListBoxItem>
<ListBoxItem>My-Very-Long-Item-Nimber-2___</ListBoxItem>
<ListBoxItem>My-Very-Long-Item-Nimber-3___</ListBoxItem>
<ListBoxItem>My-Very-Long-Item-Nimber-4___</ListBoxItem>
<ListBoxItem>My-Very-Long-Item-Nimber-5___</ListBoxItem>
</ListBox>
</HierarchicalDataTemplate>
</Window.Resources>
<Grid>
<ListBox ItemTemplate="{StaticResource ItemTemplateSchedule}" >
>
</ListBox>
</Grid>
Current screenshot:
.
UPD1
Ok, answer to my question is setting of width for internal listbox, thanks to #sa_ddam213:
Width="{Binding RelativeSource={RelativeSource FindAncestor, AncestorType=ListBox}, Path=ActualWidth}"
Now I want add some new control in each row of external listbox:
<HierarchicalDataTemplate x:Key="ItemTemplateSchedule">
<StackPanel Orientation="Horizontal" Width="{Binding RelativeSource={RelativeSource FindAncestor, AncestorType=ListBox}, Path=ActualWidth}">
<TextBlock Text="This is Text in a TextBlock"/>
<ListBox >
<ListBox.ItemsPanel>
<ItemsPanelTemplate>
<StackPanel Orientation="Horizontal" />
</ItemsPanelTemplate>
</ListBox.ItemsPanel>
<ListBoxItem>My-Very-Long-Item-Number-1___</ListBoxItem>
<ListBoxItem>My-Very-Long-Item-Number-2___</ListBoxItem>
<ListBoxItem>My-Very-Long-Item-Number-3___</ListBoxItem>
<ListBoxItem>My-Very-Long-Item-Number-4___</ListBoxItem>
<ListBoxItem>My-Very-Long-Item-Number-5___</ListBoxItem>
</ListBox>
</StackPanel>
</HierarchicalDataTemplate>
And it doesn't work now! Is it possible to solve this problem? Current screenshot:
You can use a FindAncestor to bind to the parent ListBox ActualWidth
Example:
<Window.Resources>
<HierarchicalDataTemplate x:Key="ItemTemplateSchedule">
<ListBox Width="{Binding RelativeSource={RelativeSource FindAncestor, AncestorType=ListBox}, Path=ActualWidth}" >
<ListBox.ItemsPanel>
<ItemsPanelTemplate>
<StackPanel Orientation="Horizontal" />
</ItemsPanelTemplate>
</ListBox.ItemsPanel>
<ListBoxItem>My-Very-Long-Item-Nimber-1___</ListBoxItem>
<ListBoxItem>My-Very-Long-Item-Nimber-2___</ListBoxItem>
<ListBoxItem>My-Very-Long-Item-Nimber-3___</ListBoxItem>
<ListBoxItem>My-Very-Long-Item-Nimber-4___</ListBoxItem>
<ListBoxItem>My-Very-Long-Item-Nimber-5___</ListBoxItem>
</ListBox>
</HierarchicalDataTemplate>
</Window.Resources>
Result:

Resizeable WPF ListBox / ItemsControl items

I would like to have GridSplitter-like functionality in a WPF ListBox (or ItemsControl). The following code doesn't work but demonstrates what I want to achieve:
<ListBox ItemsSource="{Binding MyCollection}">
<ListBox.ItemsPanel>
<ItemsPanelTemplate>
<StackPanel Orientation="Horizontal"/>
</ItemsPanelTemplate>
</ListBox.ItemsPanel>
<ListBox.ItemTemplate>
<DataTemplate>
<Grid>
<TextBlock Text="{Binding MyTextProperty}" Margin="0,0,10,0"/>
<GridSplitter
Width="5"
Background="Red"
HorizontalAlignment="Right"
ResizeBehavior="CurrentAndNext"/>
</Grid>
</DataTemplate>
</ListBox.ItemTemplate>
</ListBox>
Does anyone have an idea on how to implement this?
Why not use ListView GridView? GridView supports resizing columns.

How to set WrapPanel itemsource to list?

I want to show in WrapPanel a list of images. How can I do that or maybe I shall use other control ?
You can absolutely use the WrapPanel to show a list of images, scrolling vertically or horizontally. To get the kind of panoramic tile effect like in People hub with your images, you could do something like this:
<controls:PanoramaItem Header="something" Orientation="Horizontal" Margin="0,-15,0,0" >
<ListBox Name="SomeList" Margin="0,0,-12,0" ItemsSource="{Binding SomeItemsList}" >
<ListBox.ItemsPanel>
<ItemsPanelTemplate>
<toolkit:WrapPanel x:Name="wrapPanel" Width="700" />
</ItemsPanelTemplate>
</ListBox.ItemsPanel>
<ListBox.ItemTemplate>
<DataTemplate>
<StackPanel Orientation="Horizontal" Margin="0,0,0,17">
<Image Height="200" Width="200" Margin="12,0,9,0" Source="{Binding ImageURL}" />
</StackPanel>
</DataTemplate>
</ListBox.ItemTemplate>
</ListBox>
</controls:PanoramaItem>
Please note that a WrapPanel inside a ListBox does pick up the DataTemplate you define .. so you have complete liberty to bind any list to your WrapPanel.
Hope this helps!
Search for the same thing and came across this: Displaying a Collection of Items in a WrapPanel.
<ItemsControl ItemsSource="{Binding ActorList}">
<ItemsControl.ItemTemplate>
<DataTemplate>
<Image Source="{Binding Image}" Height="100"/>
</DataTemplate>
</ItemsControl.ItemTemplate>
<ItemsControl.ItemsPanel>
<ItemsPanelTemplate>
<WrapPanel/>
</ItemsPanelTemplate>
</ItemsControl.ItemsPanel>
</ItemsControl>
or you can use Xceed's SwitchPanel.
Yes definetly not the WrapPanel, it has not ItemsSource, it can't take a list.
Use the ListBox, and you can set the ItemsSource.
Edit

Move down overflow contents in horizontal stackpanel

I have a list box in expander:
<ListBox ItemsSource="{Binding MySource">
<ListBox.ItemTemplate>
<DataTemplate>
<RadioButton Content="{Binding MyContent}" />
</DataTemplate>
</ListBox.ItemTemplate>
<ListBox.ItemsPanel>
<ItemsPanelTemplate>
<StackPanel Orientation="Horizontal" />
</ItemsPanelTemplate>
</ListBox.ItemsPanel>
</ListBox>
I wrap the radio button with horizontal orientation stackpanel. I want the overflow radio buttons move down like right image shown below (no horizontal scrollbar). Now, mine is like the left one.
Stackpanel Orientation="Horizontal" http://www.empirepic.com/images/i8f5sevyzqch10uodso.jpg
You need to use a WrapPanel, not a StackPanel. In WPF it's built into the main assemblies but in Silverlight you'll need to get the Silverlight Toolkit.
<ListBox ScrollViewer.HorizontalScrollBarVisibility="Disabled" ItemsSource="{Binding MySource">
<ListBox.ItemTemplate>
<DataTemplate>
<RadioButton Content="{Binding MyContent}" />
</DataTemplate>
</ListBox.ItemTemplate>
<ListBox.ItemsPanel>
<ItemsPanelTemplate>
<t:WrapPanel />
</ItemsPanelTemplate>
</ListBox.ItemsPanel>
</ListBox>

WPF: ListBox with WrapPanel, vertical scrolling problem

I have a UserControl (XAML below) that has a ListBox that I want to display images inside a WrapPanel, where images are displayed as many as will fit on one row and then wrap onto the next row etc. It works, except when the ListBox grows higher than the available space in the window, I'm not getting a vertical scrollbar, i.e. the contents get clipped. If I set a fixed height on the ListBox, the scrollbar appears and works as expected. How can I get this listbox to grow to the available space and then show a vertical scrollbar? This control is inside StackPanel inside a Grid in the main window. If I wrap the StackPanel inside a ScrollViewer, I get the scrollbar I'm after, but that's not really a good solution if I wanted to add some more controls to the UserControl above the ListBox (e.g. image size "zoom" etc) as I wouldn't want them to scroll with the images.
Thanks!! :)
<UserControl x:Class="GalleryAdmin.UI.GalleryView"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml">
<ListBox Name="itemListBox" BorderThickness="0" ItemsSource="{Binding}" ScrollViewer.HorizontalScrollBarVisibility="Disabled">
<ListBox.ItemTemplate>
<DataTemplate>
<StackPanel Background="LightGray" Margin="5" >
<StackPanel Margin="5">
<Image Source="{Binding Path=LocalThumbPath}" Height="100" />
<TextBlock Text="{Binding Path=Name}" TextAlignment="Center"></TextBlock>
</StackPanel>
</StackPanel>
</DataTemplate>
</ListBox.ItemTemplate>
<ListBox.ItemsPanel>
<ItemsPanelTemplate>
<WrapPanel />
</ItemsPanelTemplate>
</ListBox.ItemsPanel>
</ListBox>
I think you better go with override the ItemPanelTemplate:
<Grid>
<ListBox ScrollViewer.HorizontalScrollBarVisibility="Disabled">
<ListBox.ItemsPanel>
<ItemsPanelTemplate>
<WrapPanel IsItemsHost="True" />
</ItemsPanelTemplate>
</ListBox.ItemsPanel>
<ListBoxItem>listbox item 1</ListBoxItem>
<ListBoxItem>listbox item 2</ListBoxItem>
<ListBoxItem>listbox item 3</ListBoxItem>
<ListBoxItem>listbox item 4</ListBoxItem>
<ListBoxItem>listbox item 5</ListBoxItem>
</ListBox>
Well, I finally stumbled upon the solution. I was adding my UserControl to a placeholder panel that looked like this:
<ScrollViewer Margin="20" >
<StackPanel Name="contentPanel"></StackPanel>
</ScrollViewer>
However, when I switched it to a Grid instead, things started to work the way I wanted:
<Grid Name="contentPanel" Margin="20" />
I think it has to do with the StackPanel not taking up all the vertical space by default, like the Grid is doing.
All I had to do was set the following, and the problem went away:
<ListBox ScrollViewer.HorizontalScrollBarVisibility="Disabled">
I was just looking through several questions about this issue, and although this is an old thread, this one gave me the answer, but just to clarify....
The layout GRID is the answer to most issues like this. To get the proper ListBox/WrapPanel operation to fill the available space, the following code does the trick:
<Grid Grid.Row="1" MaxHeight="105">
<ListBox ItemTemplate="{DynamicResource StoreGroupTemplate01}" ItemsSource="{Binding StoreGroupHeader}"
ScrollViewer.HorizontalScrollBarVisibility="Disabled">
<ListBox.ItemsPanel>
<ItemsPanelTemplate>
<WrapPanel Orientation="Horizontal"/>
</ItemsPanelTemplate>
</ListBox.ItemsPanel>
</ListBox>
</Grid>
I have this in another grid to place the list at the bottom of my screen (ie.. the Grid.Row="1") and you can adjust MaxHeight (or remove it) to control the visible area before the vertical scroll bar will show up.
Put your listbox inside of a ScrollViewer and then set the scrollviewer's VerticalScrollBarVisibility property to "Auto"
<ScrollViewer VerticalScrollBarVisibility="Auto" HorizontalScrollBarVisibility="Disabled">
<ListBox Name="itemListBox" BorderThickness="0" ItemsSource="{Binding}" >
<ListBox.ItemTemplate>
<DataTemplate>
<StackPanel Background="LightGray" Margin="5" >
<StackPanel Margin="5">
<Image Source="{Binding Path=LocalThumbPath}" Height="100" />
<TextBlock Text="{Binding Path=Name}" TextAlignment="Center"></TextBlock>
</StackPanel>
</StackPanel>
</DataTemplate>
</ListBox.ItemTemplate>
<ListBox.ItemsPanel>
<ItemsPanelTemplate>
<WrapPanel />
</ItemsPanelTemplate>
</ListBox.ItemsPanel>
</ListBox>
</ScrollViewer>
HTH

Resources