Dynamically adjust ListView height on adding / removing items? - c#

I have a 3 Level Nested ListView binded to the same 3 Level Nested Collection. MainItems are added at the 3rd level.
Unmodified, there are scrollbars on ALL the levels. On item added, I edit the Containing Grid of the ListViewItem to adjust the height dynamically.
I have succeeded on removing the 3rd Level Scroll Bar. However, I want to remove the 2nd Level also, which I can't seem to do.
When I try to adjust the height of the 1st Level ListViewItem, the scrollbars on the 1st Level just disappears but the height is not adjusted at all.
What I want to do is ONLY have the ScrollBar on the 1st Level and scroll from there.
Basically, something like this:
This is my current code:
<Grid x:Name="ParentGrid">
<ListView x:Name="Level1ListView"
ItemsSource="{Binding Path=Level1}">
<ListView.ItemTemplate>
<DataTemplate>
<Grid x:Name="GridLevel1">
<Grid.ColumnDefinitions>
<ColumnDefinition Width="Auto" />
<ColumnDefinition Width="*" />
</Grid.ColumnDefinitions>
<ToolKit_Controls:LayoutTransformControl Grid.Column="0">
<ToolKit_Controls:LayoutTransformControl.Transform>
<RotateTransform x:Name="rotateTransform" Angle="270"/>
</ToolKit_Controls:LayoutTransformControl.Transform>
<TextBlock Text="{Binding Path=Level1NameString}" FontSize="32" HorizontalAlignment="Center" />
</ToolKit_Controls:LayoutTransformControl>
<ListView x:Name="Level2ListView"
ItemsSource="{Binding Path=Level2}"
Grid.Column="1"
>
<ListView.ItemTemplate>
<DataTemplate>
<Grid x:Name="GridLevel2">
<Grid.RowDefinitions>
<RowDefinition Height="Auto" />
<RowDefinition Height="*" />
</Grid.RowDefinitions>
<Border BorderBrush="White" BorderThickness="1" Grid.Row="0"/>
<TextBlock Text='{Binding Path=Level2Name}' Foreground="Black" FontSize="18"
Grid.Row="0"/>
<Grid x:Name="GridLevel3" Width="300" Height="100" Grid.Row="1">
<ListView x:Name="ListView_Level3" IsSwipeEnabled="False"
ManipulationMode="None"
ItemsSource="{Binding Path=Level3DisplayCollection}"
Grid.Column="1">
<ListView.ItemContainerTransitions>
<TransitionCollection>
<EntranceThemeTransition IsStaggeringEnabled="False" />
</TransitionCollection>
</ListView.ItemContainerTransitions>
</ListView>
</Grid>
</Grid>
</DataTemplate>
</ListView.ItemTemplate>
</ListView>
</Grid>
</DataTemplate>
</ListView.ItemTemplate>
<ListView.ItemsPanel>
<ItemsPanelTemplate>
<WrapGrid Orientation="Horizontal" MaximumRowsOrColumns="1" ></WrapGrid>
</ItemsPanelTemplate>
</ListView.ItemsPanel>
</ListView>
And the important code which changes the height on item added:
var GridLevel1 = TypedAssociatedObject.GetAncestors().Where(a => a.Named("GridLevel1")).FirstOrDefault() as Grid;
//GridLevel1.Height = GridLevel1.ActualHeight + 50;
var GridLevel2 = TypedAssociatedObject.GetAncestors().Where(a => a.Named("GridLevel2")).FirstOrDefault() as Grid;
GridLevel2.Height = GridLevel2.ActualHeight + 50;
var GridLevel3 = TypedAssociatedObject.GetAncestors().Where(a => a.Named("GridLevel3")).FirstOrDefault() as Grid;
GridLevel3.Height = GridLevel3.ActualHeight + 50;
Level 1 is commented out because when I add it, although the 2nd Scroll Bar is removed the ListViewItem height doesn't change, resulting in the UI being wrong and not showing everything. You also notice that the 1st level scrollbar remains the same size:
What I want is to extend the height of Header 1 so that everything still shows and the 1st Level Scrollbar on the right is the one that extends / grows.
Can anyone help point out what I am doing wrong?
Thank you!
Edit: This is a Windows store app.

Set the ItemsPanel to StackPanel in your inner list views. This way you would not need to adjust the height of each item.
Also to hide the scrollbars use ScrollViewer.VerticalScrollBarVisibility="Hidden" on your inner list views.
Have you considered using grouping?

Related

UWP FlipView height/vertical next button issue

I am trying to get a FlipView streched to the height of its parent view. The XAML look like this:
<StackPanel Orientation="Vertical">
<FlipView x:Name="flipView"
BorderBrush="Black" BorderThickness="1"
VerticalAlignment="Stretch"
SelectionChanged="FlipView_SelectionChanged" >
<!-- Use a vertical stack panel for vertical flipping. -->
<FlipView.ItemsPanel>
<ItemsPanelTemplate>
<VirtualizingStackPanel Orientation="Vertical"/>
</ItemsPanelTemplate>
</FlipView.ItemsPanel>
</FlipView>
<TextBlock x:Name="textOutput" Text="Hello"></TextBlock>
</StackPanel>
The children of the FlipView were added in C#:
var image1 = await MakeImageForPageIndex(1);
var image2 = await MakeImageForPageIndex(2);
flipView.Items.Add(image1);
flipView.Items.Add(image2);
As you can see in the screenshot the vertical next button and the bottom border are clipped.
I have tried setting VerticalAlignment of the FlipView to Strech with no luck. Setting the images a small Height didn't help either.
I have also tired Height="{Binding RelativeSource={RelativeSource TemplatedParent}, Path=ActualHeight}" from this question
Thank you all!
StackPanel stacks its children in one direction (vertical in this case), its size grows with its children, it does not define a bound for its children.
Use a Grid to replace the StackPanel.
<Grid>
<Grid.RowDefinitions>
<RowDefinition Height="*" />
<RowDefinition Height="Auto" />
</Grid.RowDefinitions>
<FlipView x:Name="flipView" />
<TextBlock Grid.Row="1" />
</Grid>

WPF container with fix size children

I want a container that have 3 columns and in each column, the cell can wrap it's content like the picture below
So far, I've done this:
<ListBox Name="listQuestion">
<ListBox.ItemsPanel>
<ItemsPanelTemplate>
<UniformGrid Columns="3"/>
</ItemsPanelTemplate>
</ListBox.ItemsPanel>
</ListBox>
But the result is every cell have the same size as the biggest cell.
If you want to have a grid with three separate lists as their columns you should be able to use a combination of a Grid and a listbox
<Grid>
<Grid.ColumnDefinitions>
<ColumnDefinition />
<ColumnDefinition />
<ColumnDefinition />
</Grid.ColumnDefinitions>
<ListBox Grid.Column="0"/>
<ListBox Grid.Column="1"/>
<ListBox Grid.Column="2"/>
</Grid>
A grid will give you the most flexibility in your layout and allows you to have elements span multiple columns or rows. If you don't need all that flexibility you could use a stackpanel instead
<StackPanel Orientation="Horizonal">
<ListBox/>
<ListBox/>
<ListBox/>
</StackPanel>

ListBox does not use all available space within Grid.Column - WPF

I have a ListBox control that has been assigned to Grid.Column 0 which has a value of '*' defined for it's width, however when rendered there is a sizeable amount of space that is not being used.
I have also noticed that there is a border of sorts around the ListBox control itself, however I have not added one within the markup.
My UI (Areas of concern marked in Red):
My Markup:
<Window.Resources>
<DataTemplate x:Key="GameImagesTemplate" >
<StackPanel Orientation="Vertical">
<Image Source="{Binding FileInfo.FullName}" Margin="8,8,8,8" Height="70" Width="70" />
<Label Content="{Binding Name}" Width="70" />
</StackPanel>
</DataTemplate>
<DataTemplate x:Key="GameTemplate">
<StackPanel>
<Label Content="{Binding Name}" Background="Gray" FontSize="16" />
<ListBox x:Name="imageContent" ItemsSource="{Binding FileList}" ItemTemplate="{StaticResource GameImagesTemplate}" ScrollViewer.HorizontalScrollBarVisibility="Disabled" >
<ListBox.ItemsPanel>
<ItemsPanelTemplate>
<WrapPanel Orientation="Horizontal" IsItemsHost="True" />
</ItemsPanelTemplate>
</ListBox.ItemsPanel>
</ListBox>
</StackPanel>
</DataTemplate>
</Window.Resources>
<Grid>
<Grid.ColumnDefinitions>
<ColumnDefinition Width="*"/>
<ColumnDefinition Width="Auto"/>
</Grid.ColumnDefinitions>
<ListBox x:Name="ContentList" ItemTemplate="{StaticResource GameTemplate}" Grid.Column="0" ScrollViewer.HorizontalScrollBarVisibility="Disabled" />
<StackPanel Grid.Column="1" Background="DarkGray">
<Button Click="OnLoad">_Load</Button>
<Button Click="OnSave">_Save</Button>
<Button Click="OnAdd">_Add</Button>
<Button Click="OnDelete">_Delete</Button>
</StackPanel>
</Grid>
How would I go about resolving both of the issues raised. Is it the default behaviour of the ListBox control?
Many thanks
Yes, that is the default behavior.
In the case of the alignment it looks like you have a WrapPanel in each ListBoxItem which doesn't have quite enough space to put another item on line 1. The remaining space is unused because of the HorizontalContentAlignment setting on ListBox defaulting to Left. This setting is in turn bound to by the default ListBoxItem. Setting HorizontalContentAlignment="Stretch" on your ListBox should fix that.
The outer border comes from the default setting for BorderBrush and BorderThickness. Setting BorderThickness="0" will get rid of it entirely.
There are some other default Padding settings that add some spacing in the default Styles and Templates. If you want to get more into those add a ListBox to a project in Blend and make a copy of its default Template and ItemContainerStyle and check out the XAML. Also consider using the base ItemsControl in cases where you don't need selection behavior, as it doesn't have any of these type of default settings.

Creating a table with Silverlight for Windows Phone 7

I'd like to create a table on WP7. This is my current approach using a ListBox with a Grid as the data template.
<ListBox x:Name="ResultsList" Margin="12,0" Grid.Row="1">
<ListBox.Resources>
<DataTemplate x:Key="ResultsListItem">
<Grid d:DesignWidth="385" Height="28">
<Grid.ColumnDefinitions>
<ColumnDefinition Width="*"/>
<ColumnDefinition Width="88"/>
<ColumnDefinition Width="*"/>
</Grid.ColumnDefinitions>
<TextBlock x:Name="textBlock1" Margin="0,0,24,0"/>
<TextBlock x:Name="textBlock2" Margin="0,0,24,0"
VerticalAlignment="Top" Grid.Column="1"/>
<TextBlock x:Name="textBlock3" Margin="0,0,24,0"
VerticalAlignment="Top" Grid.Column="3"/>
</Grid>
</DataTemplate>
</ListBox.Resources>
<ListBox.ItemTemplate>
<StaticResource ResourceKey="ResultsListItem"/>
</ListBox.ItemTemplate>
</ListBox>
The problem is, that the resulting table's columns are not sized equally. The Grid's column definitions are applied to each row independently of the other rows. That means, if there is a long text in textBlock1, column 0 will be larger. In the next row there could be a shorter text in textBlock1, resulting in column 0 also being shorter than the column 0 in the previous row.
How can the columns in all rows be sized equally? I don't want to use fixed width because when the orientation changes from portrait to landscape the colums would resize automatically.
There is the HeaderedItemsControl, but as I understand it it is not available for Windows Phone 7?
This is a tricky problem! In WPF there exists the concept of a SharedSizeGroup, which allows you to share column widths across multiple grids, but this is not available in silverlight.
There are a few workarounds on the web:
http://www.scottlogic.co.uk/blog/colin/2010/11/using-a-grid-as-the-panel-for-an-itemscontrol/
http://databaseconsultinggroup.com/blog/2009/05/simulating_sharedsizegroup_in.html
Although neither are simple solutions.
You might also try Mike's AutoGrid:
http://whydoidoit.com/2010/10/06/automatic-grid-layout-for-silverlight/
Here is my solution using SharedSizeGroup as suggested by ColinE.
<ListBox x:Name="ResultsList">
<ListBox.Resources>
<SharedSize:SharedSizeGroup x:Key="Col1Width" />
<SharedSize:SharedSizeGroup x:Key="Col2Width" />
<SharedSize:SharedSizeGroup x:Key="Col3Width" />
<DataTemplate x:Key="ResultsListItem">
<StackPanel d:DesignWidth="385" Orientation="Horizontal">
<SharedSize:SharedSizePanel WidthGroup="{StaticResource Col1Width}">
<TextBlock x:Name="textBlock" MaxWidth="100" Text="{Binding A}"/>
</SharedSize:SharedSizePanel>
<SharedSize:SharedSizePanel WidthGroup="{StaticResource Col2Width}">
<TextBlock x:Name="textBlock1" MaxWidth="85" Text="{Binding B}"/>
</SharedSize:SharedSizePanel>
<SharedSize:SharedSizePanel WidthGroup="{StaticResource Col3Width}">
<TextBlock x:Name="textBlock2" MaxWidth="200" Text="{Binding C}"/>
</SharedSize:SharedSizePanel>
</StackPanel>
</DataTemplate>
</ListBox.Resources>
<ListBox.ItemTemplate>
<StaticResource ResourceKey="ResultsListItem"/>
</ListBox.ItemTemplate>
</ListBox>
Even the maximum with of each column can be controlled via the TextBlock's MaxWidth property. The SharedSizeGroups ensure that the TextBlocks have the same size in each row.
You can use WrapPanel. Set the following ItemsPanel in the Datatemple, you can just have textblock.
<ListBox.ItemsPanel>
<ItemsPanelTemplate>
<control:WrapPanel />
</ItemsPanelTemplate>
</ListBox.ItemsPanel>

inter related stack panel sizing

I have a recursively defined user control that needs the following properties:
there are two columns
the first contains a single border around some text
the second column contains a stack of these same type of controls (the recursive part)
if the box in the first column is shorter than the total height of the stacked boxes in the second column, the box should expand to make both columns the same height.
If the total height of the second column is shorter than the box in the first column, then the last item in the second column's stack should expand so they are the same height.
so for example, it might look like this:
Ok, so far what I have done is create a horizontal stack panel where the first item is a dock-panel containing a border and text... the second column is a vertical stack panel bound to a sublist, creating the recursive user control... like this..
<StackPanel Orientation="Horizontal" Background="AliceBlue">
<local:TMRequirementView Requirement="{Binding Baseline}" />
<StackPanel Orientation="Vertical">
<ItemsControl ItemsSource="{Binding Requirements}">
<ItemsControl.ItemTemplate>
<DataTemplate>
<local:TMGridView Baseline="{Binding}" />
</DataTemplate>
</ItemsControl.ItemTemplate>
</ItemsControl>
</StackPanel>
Where the requirement looks like this:
<DockPanel>
<Border MinHeight="50"
BorderBrush="Black" BorderThickness="2">
<TextBlock Text="{Binding Description}"
TextWrapping="Wrap" Background="Transparent" Height="Auto" />
</Border>
</DockPanel>
Now this works great if the stacked column is taller, but it doesn't work if the first column is taller, and I get gaps. Any idea how to handle this mutual height dependency?
Update:
So by adding a border around the right columns stack panel, I was able to see that the stackpanel actually did receive the min-height changes. However, even though there was room to expand, the children of the stack panel didn't automatically update. If I fix the minheight of the stack panel before hand to something large, the children fill up. What I need to figure out is how to update the chidren's height based on changes to the stack panel's min-height.
I think the Grid in this layout does what you describe. I put it in a DockPanel so that you can see how it resizes. Try typing stuff into the text boxes and watch how it behaves:
<Page
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml">
<DockPanel>
<Grid DockPanel.Dock="Top">
<Grid.ColumnDefinitions>
<ColumnDefinition Width="*"/>
<ColumnDefinition Width="*"/>
</Grid.ColumnDefinitions>
<Grid.RowDefinitions>
<RowDefinition Height="Auto"/>
<RowDefinition Height="Auto"/>
<RowDefinition Height="*"/>
</Grid.RowDefinitions>
<TextBox AcceptsReturn="True" Grid.Row="0" Grid.Column="0" Grid.RowSpan="3"></TextBox>
<TextBox AcceptsReturn="True" Grid.Row="0" Grid.Column="1"></TextBox>
<TextBox AcceptsReturn="True" Grid.Row="1" Grid.Column="1"></TextBox>
<TextBox AcceptsReturn="True" Grid.Row="2" Grid.Column="1"></TextBox>
</Grid>
<TextBlock/>
</DockPanel>
</Page>
All three rows of the Grid will have the height of a TextBox at a minimum (when you replace the TextBoxes with other elements, you'll need to set minimum heights to keep them from vanishing if they're empty). Since the third row is star-sized, it will size itself to all remaining vertical space left after the first two rows are arranged. So if there's a bunch of content in the first column, the third row in the second column gets taller.
Edit
Actually, there's no reason to even screw around with a Grid in this case: What you're describing is really the behavior of the DockPanel:
<DockPanel>
<DockPanel DockPanel.Dock="Top">
<DockPanel.Resources>
<Style TargetType="Label">
<Setter Property="DockPanel.Dock" Value="Top"/>
<Setter Property="Background" Value="Lavender"/>
<Setter Property="Margin" Value="1"/>
</Style>
</DockPanel.Resources>
<DockPanel LastChildFill="True">
<Label>Foo</Label>
</DockPanel>
<DockPanel LastChildFill="True">
<Label>Foo</Label>
<Label>Bar</Label>
<Label>Baz</Label>
<Label>Bat</Label>
</DockPanel>
</DockPanel>
<Label/>
</DockPanel>

Categories

Resources