Resizing Listbox Contents according to Listbox dimensions - wpf

I am attempting to resize the contents of my listbox according to the listbox itself. This is being done in WPF.
Any ideas on how this might be possible?

I assume when you say "resize" you mean that you want to stretch the items in both directions. To take a default ListBox and stretch the items horizontally all you need is:
<ListBox HorizontalContentAlignment="Stretch"/>
The default is Left so all the ListBoxItems end up pushed to the left and sized individually based on their content.
Vertical stretching requires getting rid of the StackPanel used to do layout for the items because it has no concept of resizing its children in the direction of Orientation. The simplest thing to use is a UniformGrid but you might want something more custom depending on how you want the items to size relative to each other. You'll also need to do the same thing with the VerticalContentAlignment setting (Center by default). So here's one that will stretch items both ways:
<ListBox HorizontalContentAlignment="Stretch" VerticalContentAlignment="Stretch">
<ListBox.ItemsPanel>
<ItemsPanelTemplate>
<UniformGrid Columns="1"/>
</ItemsPanelTemplate>
</ListBox.ItemsPanel>
</ListBox>

Related

XAML List conent from left to right, top to bottom

I am using a WPF user control and a listview which is bound to some items. I would like to display the items in the listview from left to right, and then top to bottom.
So far I have tried to put the code in a WrapPanel which is in a ItemPanel, but this only placed the items horizontally in a line!
<ListView Height="421" Width="500" x:Name="ReportsListBox" ItemTemplate="{DynamicResource ReportsTemplate}" VerticalContentAlignment="Center" MaxWidth="500">
<ListBox.ItemsPanel>
<ItemsPanelTemplate>
<WrapPanel Orientation="Horizontal"/>
</ItemsPanelTemplate>
</ListBox.ItemsPanel>
</ListView>
Anyone know what I should do? I've searched the internet for this, but couldn't find much...
Thanks
As it looks like you already know, a WrapPanel with an Orientation of Horizontal will display items from left to right until it reaches the maximum horizontal size of its container, at which point it will wrap down to the next row.
Not sure if this is the issue you are seeing, but a ListView has a ScrollViewer built in. As such, your WrapPanel will never reach the maximum horizontal size if its container, as the ScrollViewer will always allow more space.
Try something like this:
<ListView ScrollViewer.HorizontalScrollBarVisibility="Disabled">
...
</ListView>
With the horizontal scroll disabled, the WrapPanel will be able to reach the maximum width of the container and will wrap as expected.
Does this help?

WPF ContentControl width grows but doesn't shrink when wrapped in a ScrollViewer

I'm trying to figure out how to make my ContentControl to correctly scroll Horizontally (Vertically its fine at the moment). By correctly i mean i would like to see the content to stretch (expand infinitely) while having minimum sizes to which a scrollbar would appear in order for the content not to overflow behind the ContentControl's area, so here's a quick introduction:
The main window is structured in this way:
Grid (2 columns of .3* and .7*)
Border
Grid (7 rows, one set to * where ContentControl is)
ScrollViewer with StackPanel (purely for test) wrapping a ContentControl that has Auto Width
ContentControl's Template:
Grid (Width set to UserControl's ActualWidth, 6 rows with one set to Auto where ItemsControl go
ItemsControl that describes an ItemTemplate of a type DataTemplate which contains a Grid inside of which i have a DataGrid
The actual problem is that the ContentControl grows as you resize the window, but does not shrink with window resize.
Main View XAML (truncated for clarity):
<ScrollViewer Grid.Row="5" VerticalScrollBarVisibility="Auto" HorizontalScrollBarVisibility="Auto">
<ContentControl Grid.Row="5" Background="Transparent" Focusable="False" Margin="0,5,0,0"
Content="{Binding CurrentSection}" ContentTemplateSelector="{StaticResource templateSelector}/>
</ScrollViewer>
Tempate XAML (truncated for clarity):
<Grid>
...
<ItemsControl Grid.Row="4" ItemsSource="{Binding Data.QualifyingDistributionsDividends}" x:Name="QualifyingItemsControl">
<ItemsControl.ItemTemplate>
<DataTemplate>
<Grid x:Name="DTLayoutGrid">
...
<Grid Grid.Row="1" x:Name="DataLayout" Width="{Binding ElementName=DTLayoutGrid, Path=ActualWidth}" HorizontalAlignment="Stretch">
...
<DataGrid Grid.Row="1" Grid.Column="0" Grid.ColumnSpan="8" HorizontalScrollBarVisibility="Disabled"
ItemsSource="{Binding Payments}" Style="{StaticResource DataGridStyle}" CellStyle="{StaticResource DataGridNormalCellStyle}">
</DataGrid>
</Grid>
</Grid>
</DataTemplate>
</ItemsControl.ItemTemplate>
</ItemsControl>
</Grid>
So what happens? Datagrid assumes width of the entire DataTemplate (well its underlying controls that are set to be DataTemplates size, then * column assumes all empty space. When you try to resize the entire window that holds this code it will grow correctly, expanding the * column but it seems shrinking is not "registered" and it keeps the size you expanded it to, applies a scrollbar over that and forgets about it.
What i've tried so far was to set widths for ItemsControl, its underlying parents like Grid etc, also setting size to ContentControl, StackPanel, ScrollViewer and parent Grid of that.
I've also tried using scrollviewers directly on the Datagrid which produces an epileptic "1 million resizes a second" scenario. I've also played around with HorizontalAlignments
Under certain situations i DID managed to get the horizontal scrollbar to appear correctly but unfortunately that makes my DataGrid's * column to assume Auto Width rather then Star so DataGrid starts having an empty area to the right (unacceptable unfortunately...)
I understand that in order for horizontal scrollbar to work the parent or child of the scrollviewer needs Width set, i guess i can't work out where exactly do i need to restrict it. DataGrids NEED to infinitely expand with the main window while having first column fill all the available space.
Do let me now if you need more information on this and I will gladly answer.
It seems to me that this is just another case of the dreaded StackPanel layout problem. This problem comes up again and again and I confess that I had the very same problem when I started learning WPF. The StackPanel does not take the available size of its parent into consideration whereas other Panels such as a DockPanel or a Grid (yes, that's actually a Panel too) do.
It's explained in the How to: Choose Between StackPanel and DockPanel page on MSDN:
Although you can use either DockPanel or StackPanel to stack child elements, the two controls do not always produce the same results. For example, the order that you place child elements can affect the size of child elements in a DockPanel but not in a StackPanel. This different behavior occurs because StackPanel measures in the direction of stacking at Double.PositiveInfinity; however, DockPanel measures only the available size.
The StackPanel should only really be used to align a number of items, such as Buttons or other controls in a straight line where available space is not a concern. So anyway, the solution should be simple... just remove the StackPanel from the ScrollViewer. It doesn't appear to serve any purpose there anyway.
UPDATE >>>
After looking again, it seems as though you're saying that the problem is inside the DataTemplate, right? You might be able to fix that by setting the ItemsControl.HorizontalContentAlignment property to Stretch. That would ensure that each item remains within the boundary of the ItemsControl.
I'd also remove your Binding on the Grid.Width as you don't need it... a child Grid will take up the full space of a parent Grid by default. If these ideas don't work, just simplify your problem. Seriously, if you follow the advise in the linked page from the Help Center that I gave you in the comments, then you'll either fix the problem, or be able to come back here and provide a complete, but concise example that we could test.
I've found the behavior I was looking for by using a UniformGrid as the ItemsPanel, with its rows bound to the count of the ItemsSource model:
<ScrollViewer>
<ItemsControl ItemsSource="{Binding MyCollection}">
<ItemsControl.ItemsPanel>
<ItemsPanelTemplate>
<UniformGrid Rows="{Binding MyCollection.Count}" />
</ItemsPanelTemplate>
</ItemsControl.ItemsPanel>
<ItemsControl.ItemTemplate>
<DataTemplate>
...
</DataTemplate>
</ItemsControl.ItemTemplate>
</ItemsControl>
</ScrollViewer>
As #Sheridan pointed out above, it seems the StackPanel is causing trouble. Also, credit to https://stackoverflow.com/a/23375262/385273 for pointing out the UniformGrid option.

Silverlight stackpanel Orientation Horizontal last element fill to infinite

In a scenario like this:
<StackPanel x:Name="StackPanel1" VerticalAlignment="Stretch" HorizontalAlignment="Stretch" Orientation="Horizontal">
<Element1/>
<Element2>
</StackPanel>
It possible to stretch last element (Element2) in control list to fit all possible space (like width="*")?
I am forced to use a grid?
The StackPanel content area collapses to fit the children. Stretch in the direction that grows on a StackPanel is only useful for painting the background. It does not affect the children.
Use a grid or a custom container.

adding rows dynamically based on the records in database in listbox mvvm mvvm light

I have a listbox in which I am displaying the records from the database. Its coming one after the other in a single column. How to put the records programitically as 3 rows and 3 columns i.e. 3 records in a row, after that 3 records in a row. Kindly suggest?
Thanks.
If the records are (or can be) a fixed width, it is easy: Just change your ListBox.ItemsPanel to a WrapPanel and set the ListBox width to be just over 3x the width of the items:
<DataTemplate DataType="{x:Type my:CustomItem}">
<Border Width="100" ...>
...
</Border>
</DataTemplate>
...
<ListBox ... Width="320">
<ListBox.ItemsPanel>
<ItemsPanelTemplate>
<WrapPanel/>
</ItemsPanelTemplate>
</ListBox.ItemsPanel>
...
</ListBox>
If you need to divide the available width by three and you know that all of your items are exactly the same height (or if you are ok with all your rows being the max height of any item), there is a very simple solution using UniformGrid with no Height specified:
<ListBox ... >
<ListBox.ItemsPanel>
<ItemsPanelTemplate>
<UniformGrid Width="3" />
</ItemsPanelTemplate>
</ListBox.ItemsPanel>
...
</ListBox>
If you want to divide the available width by 3 to get the item width but stack the items as closely as possible vertically, it is possible but tricky in pure XAML. (I wouldn't recommend doing it in pure XAML but if you want to do it that way, you can create a hidden Grid with three star-sized columns and a fixed-width column, then use a binding to the ActualWidth of the first column of the hidden grid.)
An easier way is to create a simple custom panel that acts like UniformGrid horizontally but StackPanel vertically. This is a very simple Panel subclass:
MeasureOverride computes desired width as 3* max width of any child
MeasureOverride computes desired height as sum(max(height of each group of 3))
ArrangeOverride lays out children 3 per row, each DesiredWidth/3 to the right of the previous one, and the next row being max(height) down from the current row
Obviously if you design a custom panel you wouldn't hard-code the "3" - you would make it a property, probably a DependencyProperty, so you can easily change it and so that you can reuse your panel elsewhere if need be.

WPF GridView: "Newspaper" Column?

I'm not sure how else to describe this, outside of calling it a "newspaper" column.
Essentially I have a potentially long list of codes that I want to display in a grid, and I have limited vertical real estate. I would like to show these codes (which are all from the same database column) in multiple columns, maybe 3-5 columns across.
I can absolutely break the data up into separate sources and bind to them separately if that is the best solution, but I thought there might be an easy, built-in way to accomplish this with WPF.
This is actually trivial using a WrapPanel.
For a hard-coded list:
<WrapPanel Orientation="Vertical">
<ItemOne />
<ItemTwo />
...
</WrapPanel>
For a data-bound list:
<ItemsControl ItemsSource="...">
<ItemsControl.ItemsPanel>
<ItemsPanelTemplate>
<WrapPanel Orientation="Vertical" />
</ItemsPanelTemplate>
</ItemsControl.ItemsPanel>
<ItemsControl.ItemTemplate>
<DataTemplate DataType="...">
...
</DataTemplate>
</ItemsControl.ItemTemplate>
</ItemsControl>
If desired you can replace the ItemsControl with a ListBox or make it a ComboBox or whatever. You can use a default template for your data or use a custom template as shown above. You can even use a ListView along with a GridView if you want a multi-column list.
I suspect what you're looking at here is a custom layout panel which has a well defined height and then wraps into the next column. You could then use the ItemsPanelTemplate of the list control to use your new custom panel.
With respect to the development of the panel itself, I would suspect that either wrapping or inheriting from the Grid would be an excellent first choice. The panel could then manage the column definitions itself based on the number of items it contains.
To determine the layout of the individual items, I suspect using the ActualHeight to determine when another item would cause a column to overflow and using that to move to the next column would be the optimal solution. I would imagine using a single vertical stack panel with no border or padding inside each column may make it easier for your to offload the layout to those controls, but I believe you would still wind up having to determine which panel to lay the items out in based on the item heights.

Resources