WPF Stackpanel height not resizing when removing a usercontrol - c#

I have a stackpanel in a grid row with the row height set to auto.
I add user controls at runtime and the height resizes fine, when removing the user controls the height does not reduce though. I have tried to clear the stackpanel children, remove them one by one and also implemented IDisposable in each user control but when the child count shows zero the height has not reduced.
Sample XAML below, any help would be welcomed please?
<Grid x:Name="TestGrid">
<Grid.RowDefinitions>
<RowDefinition Height="Auto" />
<RowDefinition Height="Auto" />
</Grid.RowDefinitions>
<StackPanel Orientation="Horizontal">
<TextBlock Text="Test Header" Style="{StaticResource SubHeaderTextBlock}" />
</StackPanel>
<StackPanel x:Name="ChildItems" Grid.Row="1" />
</Grid>

Replace the StackPanel with a Grid. Grids stretch and retract better than StackPanels.

Instated of removing put Visibility to Collapsed

Related

How to make a certain section scrollable

I have got the following XAML:
<StackPanel HorizontalAlignment="Center">
<Image Name="logo" Source="logo.png" Margin="0,0,0,50"/>
<ScrollViewer>
<Dashboard_Control:AlignableWrapPanel x:Name="wrapPanel"/>
</ScrollViewer>
<TextBlock FontWeight="Bold" HorizontalAlignment="Center" x:Name="txtBottomText"></TextBlock>
</StackPanel>
I would like that the wrapPanel is scrollable only, so that the txtBottomText control will always be at the bottom as you scroll, and the logo image control will always be at the top - essentially only allowing the wrapPanel to be scrollable.
I have tried adding a ScrollViewer as shown above, however it never shows. I even tried adding a property to always have the vertical scrollbar, however it appears without letting me scroll (the scrollbar is disabled).
I suspect that this is because my wrapPanel's content is dynamically generated at run-time like so:
wrapPanel.Children.Add(content);
Any ideas what I can do to fix this?
It's not because of your wrapPanel's content. but because you're using a StackPanel to contain everything.
StackPanels grow indefinitely in the direction determined by their Orientation property. By default, that's vertically.
In your case, that makes the ScrollViewer "think" it has enough available space to stretch itself to accomodate its content, instead of activating the scroll bars. So it simply gets bigger as the WrapPanel inside gets bigger, pushing the TextBlock down.
To avoid this, you need to use a different Panel that is able to properly assign the available space to each control. Like a Grid.
<Grid HorizontalAlignment="Center">
<Grid.RowDefinitions>
<RowDefinition Height="Auto" />
<RowDefinition Height="*" />
<RowDefinition Height="Auto" />
</Grid.RowDefinitions>
<Image Name="logo" Source="logo.png" Margin="0,0,0,50"/>
<ScrollViewer Grid.Row="1">
<Dashboard_Control:AlignableWrapPanel x:Name="wrapPanel"/>
</ScrollViewer>
<TextBlock Grid.Row="2" FontWeight="Bold" HorizontalAlignment="Center" x:Name="txtBottomText"></TextBlock>
</Grid>
I usually say that StackPanels tend to be overused :P They're practical and easy to use, but they have a bunch of quirks and limitations that make them not suitable for many situations, like this one.
EDIT: Make sure, also, that the Grid is not contained inside another vertical StackPanel, a Grid row with Height set to Auto, or something like that.
If the Height of your WrapPanel exceeds the height of the control or window where you have put the controls, the Textblock below the Wrap Panel inside the Stack Panel is put after the Wrap panel and so it is below the scroll area.
To be able to leave the Textblock always visible you have two means:
1) limit the height of your Wrap panel
2) Use a container like a Grid with 3 rows instead of the stack panel and put the Row Heights of the Grid respectively to
Auto, *, Auto so that the image on top and the textblock on bottom use the space of their content and the Scroll panel uses all the space remaining
<Grid>
<Grid.RowDefinitions>
<RowDefinition Height="Auto"/>
<RowDefinition Height="*"/>
<RowDefinition Height="Auto"/>
</Grid.RowDefinitions>
<Image Grid.Row ="0" Source="myimage.jpg" />
<ScrollViewer Grid.Row="1">
<WrapPanel Height="1200" Width="600">
<TextBlock>Ciao sono io</TextBlock>
</WrapPanel>
</ScrollViewer>
<TextBox Grid.Row="2" TextWrapping="Wrap" HorizontalAlignment="Stretch" VerticalAlignment="Stretch" Text="IO c'ero" />
</Grid>
You have to set a fixed heigh to your scrollviewer - if not, the scrollviewer takes as much space as he needs, in order to show the complete content of its children.
Solutions:
Set the Height property of your scollviewer
Use a grid instead of a stackpanel an set the first and third rowheight to auto

WPF shrink other conent when Expander is Expanded

Whenever Expander is expanded I would like to shrink grid cell above containing ListBox, so that you can always access every ListItem(if the listbox's grid cell would not shrink, lowest part would be inacessible). To illustrate:
item item *scrollbar*
item -> item *scrollbar*
item expanderItems
expander expander
I found bunch of threads for resizable expander, but none mentioning resizing other content. The problem is, grid containing listbox in 1st row and expander in 2nd with 2nd row Height set to Auto do not resize itself when expander is expanded.
<Grid.RowDefinitions>
<RowDefinition Height="1*"/>
<RowDefinition Height="Auto"/>
</Grid.RowDefinitions>
I managed to code an ugly workaround using Expanded/Collapsed events:
private void Expander_Expanded(object sender, System.Windows.RoutedEventArgs e)
{
//grid1.Height is named content of expander
this.LayoutRoot.RowDefinitions[1].Height = new GridLength(this.LayoutRoot.RowDefinitions[1].ActualHeight + grid1.Height, GridUnitType.Pixel);
this.LayoutRoot.RowDefinitions[0].Height = new GridLength(1, GridUnitType.Star);
}
What would be the proper way? Preferably with no code behind and more "automated".
EDIT: xaml
<Grid x:Name="LayoutRoot">
<Grid.RowDefinitions>
<RowDefinition Height="1*"/>
<RowDefinition Height="Auto"/>
</Grid.RowDefinitions>
<Expander Header="Expander" Margin="0" Grid.Row="1" VerticalAlignment="Bottom" Height="23" Panel.ZIndex="1" ExpandDirection="Up" Grid.RowSpan="2" Expanded="Expander_Expanded" Collapsed="Expander_Collapsed">
<Grid x:Name="grid1" Background="#FF762CF7" Height="100" Margin="0,-100,0,0"/>
</Expander>
<ListBox Margin="0" Background="#19FFFFFF">
<Button Height="150" Width="100"/>
<Button Height="150" Width="100"/>
<Button Height="150" Width="100"/>
</ListBox>
<Grid Margin="0" Grid.Row="1" Background="#FFAEFFAE"/>
<Grid Margin="0" Background="#FFFFD8D8"/>
</Grid>
The main problem you have is setting the Height property of the Expander. It changes its height when you expand it. But if you are setting it, it has to respect the height you gave it and cannot properly expand.
Instead of setting the Height, I would set the MinHeight (or completely remove height constraints, depending on what you want to do).
Additionally you should remove the Margin of the grid inside the expander.

ListView Inside a Grid inside a ScrollViewer

I have a ListView inside a Grid which in turn is inside an "overall ScrollViewer".
Users should be able to scroll across the entire page horizontally and then scroll vertically down several child list like elements. While I am able to scroll horizontally, placing the outer ScrollViewer around the page content breaks my ListViews
Here is a cut down version of my XAML setup:
<Grid Background="{ThemeResource ApplicationPageBackgroundThemeBrush}">
<Grid.RowDefinitions>
<RowDefinition Height="140" />
<RowDefinition Height="Auto" />
</Grid.RowDefinitions>
<TextBlock x:Uid="Title" Text="Title"/>
<ScrollViewer Grid.Row="1" ZoomMode="Disabled"
VerticalScrollBarVisibility="Hidden"
HorizontalScrollBarVisibility="Auto"
VerticalScrollMode="Disabled"
HorizontalScrollMode="Enabled">
<Grid>
<Grid.ColumnDefinitions>
<ColumnDefinition Width="380" />
<ColumnDefinition />
</Grid.ColumnDefinitions>
<!--My List-->
<ListView x:Name="MyList" Grid.Column="0" />
<Grid x:Name="AppointmentDetailView" Grid.Column="1">
<!--Some other stuff-->
</Grid>
</Grid>
</ScrollViewer>
</Grid>
If I set a fixed height on any parent of the ListView or the ListView itself the scrolling works as expected but fixing the height is undesirable for screens of varying sizes. I tried binding to the ActualHeight of the ListViews parents but no luck.
It seems like the ScrollViewers children are not constrained to the height available even when the ScrollViewer.VerticalScrollMode is disabled. Seems rather odd to me, I would have expected the ScrollViewer's layout logic to be similar to Grid in the direction it has been disabled.
Any help with this is appreciated, Thank you!
I found a workaround that involves wrapping my ScrollViewer in a Grid and binding to the outer Grids ActualHeightProperty on the child element of the ScrollViewer. its a bit of a hack but does what I need it to and goes something like this
<Grid x:Name="ScrollViewerContainer" ...>
<ScrollViewer VerticalScrollMode="Disabled" ...>
<!--Page Content-->
<Grid Height="{Binding ActualHeight, ElementName=ScrollViewerContainer}" ...>
....
Personally I feel like the ScrollViewer should not allow its children to determine its Width/Height when the scroll mode is disabled in a particular direction as it breaks nested ScrollViewer's. It should revert back to the available space. But hey, I'm not Microsoft..

ScrollBar is not showing in WPF ListView which is inside nested User and Content Controls

Please help me in this issue of scroll bar visibility in WPF listview.
I have a listview inside a Content Control.
This Content Control is inside a User Control.
This User Control is inside a TabItem.
The listview has around 12 columns to display, which exceeds the window width.
I tried so many ways to show the horizontal scroll bar in the listview.
Below shown is the XAML of the Outer UserControl [width is not set for this outer usrCrtl]
<Grid>
<Grid.RowDefinitions>
<RowDefinition Height="Auto" />
<RowDefinition Height="*" /> // Here I have a custom content control
<RowDefinition Height="Auto" />
</Grid.RowDefinitions>
<MyCustomContentControl Grid.Row=1 VerticalAlignment="Stretch"......>
<TabControl>
<TabItem Header="One" Name="Tab1">
<my:usrAControl /> // I have listview inside this userctrl
</TabItem>
</TabControl>
<TabControl Header="Two" Name="Tab2" />
</MyCustomContentControl>
</Grid>
Now below is the usrAControl XAML details
<UserControl x:Class="MyProject.MyModule.usrAControl"
MinWidth="640">
// Again inside another custom user control as its child.
<usrBControl>
<Grid>
<Grid.RowDefinitions>
<RowDefinition Height="30" /> // here another headers
<RowDefinition Height="*" /> // here my listview placed
</Grid.RowDefinitions>
<ListView ScrollViewer.HorizontalScrollBarVisibility="Auto" Grid.Row="1"
Width="{Binding RelativeSource={RelativeSource FindAncestor, AncestorType={x:Type UserControl}}, Path=Width}">
// Around 12 columns which exceeds window width
</ListView>
</Grid>
</usrBControl>
</usrAControl>
I tried with lot of combination.
I initially put a scrollviewer control inside the tabitem and placed usrAControl inside it.
But it did not work.
But I want the listview should show its both scroll bars. Is any way to do it.?
Without seeing more code, my guess would be that the MinSize="640" is your problem: the ListView gets enough space from its container so it doesn't show the scroll, but the container gets clipped.
And you should get rid of the ListView Width binding, it's completely redundant.

Wrap panel where items in a row share height

i want to add squares to a panel and have them wrapped like the wrap panel.
I then want to make each square horizontally resizable individually, but when it is resized vertically, i need it to affect all the items in it's row.
Basically, I'd want all items in a row to always share the same height, but give the user a method of choosing this height (of course, each row can have its own height, and when squares wrapped to a new row they will need to inherit the new height).
Btw, those "squares" are just user controls or data template applied to a listbox items source. Can i use the same binding on a wrap panel, ad maybe i need to choose a different solution?
Thank you
you can try and put each "rectangle" in a Grid with one row and one column, and then use SharedSizeGroup on the RowDefinition. Be sure to also put Grid.IsSharedSizeScope="True" on the container:
<WrapPanel Grid.IsSharedSizeScope="True">
<Grid>
<Grid.RowDefinitions>
<RowDefinition SharedSizeGroup="Group1" />
</Grid.RowDefinitions>
<Button Height="40" Content="Hello" />
</Grid>
<Grid>
<Grid.RowDefinitions>
<RowDefinition SharedSizeGroup="Group1" />
</Grid.RowDefinitions>
<Button Content="Hello2" />
</Grid>
</WrapPanel>

Categories

Resources