Not able to stretch an inner StackPanel - c#

Usingthe setup below, I can color the whole width of the window purplish. The inner stack panel is chartreusian and shifted to the left.
<StackPanel HorizontalAlignment="Stretch"
Orientation="Horizontal"
Background="BlueViolet"
Height="70">
<StackPanel HorizontalAlignment="Left"
Orientation="Horizontal"
Background="Chartreuse" >
I was expecting that if I changed the horizontal alignment of the inner stack panel to streched, it'd fill out all the width as well but that doesn't happen. I've tried both right and streched alignments and it seems that it's not affecting the width of the inner control.
According to the posts I've found that is the way to achieve it (and it certainly worked for the outer control). What can I be missing? I've removed the other controls declared in the outer panel (i.e. all the siblings to the chartreusily colored one) with no difference.

A StackPanel will provide to its content as much space as required but also only as few as necessary.
If you want to fill exactly the width of the window, just replace the outer StackPanel by a Grid
If you want the StackPanel to fill at least the whole with, you can bind the MinWidth to its parent ActualWidth:
<StackPanel HorizontalAlignment="Stretch"
Name="parent"
Orientation="Horizontal"
Background="BlueViolet"
Height="70">
<StackPanel HorizontalAlignment="Stretch"
MinWidth="{Binding Path=ActualWidth, ElementName=parent}"
Orientation="Horizontal"
Background="Chartreuse" >
</StackPanel>
</StackPanel>

I spent a lot of time in the past struggling with stackpanels.
Here is what happens:
Your outer stackpanel (#1) has horizontal orientation, what means, that it can fill as many childs as needed, stacking them horizontally. Whenever child is rendered, there is a dialog between child and parent:
--(Child) I want to render and I have this size. Can you provide me enought space?
--(Parent) I'll do calculations and we'll see how it goes.
In case of nested stackpanels your outer stackpanel tries to stretch and demands infinite width and it's parent grid gives him just all the width he has.
But the purpose of stackpanel is to be infinite in one direction and if it's child asks for infinite width (what inner stackpanel does, when you set horizontal alignment to stretch) then we just give him minimum amount of width, since otherwise they would grow out of control and consume all memory on your PC.
So this is just an artistic view on what happens and it can be inaccurate.
Update:
Putting things simply: You can't set horizontal alignment to stretch for a child of a stackpanel with horizontal orientationand you can't set vertical alignment to stretch for a child of a stackpanel with vertical orientation.
Well, you can, but it won't stretch, because if it could, then it would have stretched infinitely
Answer: Replace inner or outer stackpanel with a grid. The fact, that you are using 2 nested stackpanels with a same orientation says that you are doing something wrong. To be honest, the only application of stackpanel, in my opinion, is inside of a scrollviewer. In other cases it's better to use WrapPanel.

I too struggle with this and provide this solution incase someone else is looking for a similar solution.
My particular issue was I needed to get the Hamburger Menu to the top and out of the SplitView. I was then trying to get the stackpanel to fill out the whole region below. This works well and a screen shot below shows what it looks like.
Hope this helps and happy to be corrected if this is not best practise.
<Grid Background="{ThemeResource AppBarToggleButtonCheckedPointerOverBackgroundThemeBrush}">
<Grid.RowDefinitions>
<RowDefinition Height="Auto" />
<RowDefinition Height="*" />
</Grid.RowDefinitions>
<StackPanel Height="50" Grid.Row="0">
<StackPanel Background="Gray" Height="50" HorizontalAlignment="Stretch">
<Button x:Name="HamburgerButton" FontFamily="Segoe MDL2 Assets" Content=""
Width="50" Height="50" Background="Transparent" Click="HamburgerButton_Click"/>
</StackPanel>
</StackPanel>
<SplitView Grid.Row="1" x:Name="MySplitView" DisplayMode="Overlay" IsPaneOpen="False"
CompactPaneLength="1" OpenPaneLength="150" VerticalAlignment="Stretch">
<SplitView.Pane >
<StackPanel >
<StackPanel Orientation="Horizontal">
<Button x:Name="LogIn" FontFamily="Segoe MDL2 Assets" Content="" Width="50" Height="50" Background="Transparent"/>
<TextBlock Text="Log In" FontSize="18" VerticalAlignment="Center" />
</StackPanel>
<StackPanel Orientation="Horizontal">
<Button x:Name="SignUp" FontFamily="Segoe MDL2 Assets" Content="" Width="50" Height="50" Background="Transparent"/>
<TextBlock Text="Sign Up" FontSize="18" VerticalAlignment="Center" />
</StackPanel>
</StackPanel>
</SplitView.Pane>
<SplitView.Content>
<Grid VerticalAlignment="Stretch">
</Grid>
</SplitView.Content>
</SplitView>
</Grid>
Menu close:
Menu open:

Related

Why is this border not moving to the vertical center of the parent StackPanel but does so in a Grid?

Within my Grid I have the following StackPanel:
<StackPanel Grid.Row="6" Grid.Column="4" Margin="5, 5, 10, 5" VerticalAlignment="Stretch" Background="Yellow" Orientation="Vertical">
<Border Background="LightGray" BorderThickness="1" BorderBrush="Black" VerticalAlignment="Center">
<StackPanel Orientation="Vertical">
<Button BorderThickness="0" Background="Transparent" Margin="0 10" HorizontalAlignment="Center">
<Button.Content>
<Image Source="\Resources\Arrow2 Up.ico"/>
</Button.Content>
</Button>
<Button BorderThickness="0" Background="Transparent" Margin="0 10" HorizontalAlignment="Center">
<Button.Content>
<Image Source="\Resources\Arrow2 Down.ico"/>
</Button.Content>
</Button>
</StackPanel>
</Border>
</StackPanel>
I have made the background yellow, so we can see the size of the StackPanel. The whole thing looks as follows:
I want to have the button in the vertical center. I can achieve that by replacing the outer StackPanel with another Grid and we get the following.
It seems like StackPanels do not know their own actual height but Grids do? Why is that the case, or is there another reason for this behavior?
A StackPanel by definition stacks elements vertically from top to bottom or horizontally from left to right (or right to left with FlowDirection="RightToLeft") depending on its Orientation.
Arranges child elements into a single line that can be oriented horizontally or vertically.
That is all it does, it does not take into account proportional sizes based on the available space. A Grid on the other hand has columns and rows that can take advantage of star sizing to achieve exactly that.
Columns and rows that are defined within a Grid can take advantage of Star sizing to distribute remaining space proportionally. When Star is selected as the height or width of a row or column, that column or row receives a weighted proportion of the remaining available space.
In your case you may not even need a StackPanel. You could just place your Border directly inside the Grid and set its VerticalAlignment and HorizontalAligment properties accordingly e.g:
<Border Grid.Row="6" Grid.Column="4" Margin="5, 5, 10, 5" Background="LightGray" BorderThickness="1" BorderBrush="Black" VerticalAlignment="Center">

Stretching textblock and texbox in stackpannel

i want to auto stretching elements horizontally to grid width, so when you stretch window elements must proportionally stretched with it.
<Grid Margin="0,0,0,40" Name="TaskGrid" Visibility="Hidden">
<StackPanel Name="AmountOfSP" Visibility="Collapsed" Orientation="Horizontal" HorizontalAlignment="Stretch">
<CheckBox Name="restrRadioButton" Checked="restrCheckBox_Checked" Unchecked="restrCheckBox_Unchecked"/>
<TextBlock TextWrapping="Wrap" Text="bla-bla" />
<TextBox Name="AmountOfO" HorizontalAlignment="Stretch" MinWidth="70" Height="20" Margin="10,0,0,0"/>
</StackPanel>
</Grid>
As I've answered here you can't use a StackPanel to strech in the stacking direction, because it will always use the smallest possible size for the stacking elements (unless they have a fixed size, then it will utilize that).
Use a DockPanel or Grid instead and order the inner components appropriately to stretch to the full size.
Adding one more option along with the mentioned answer. You can also make use of UniformGrid to achieve what you want.
<Grid Margin="0,0,0,40" Name="TaskGrid">
<UniformGrid Name="AmountOfSP" Columns="3" HorizontalAlignment="Stretch">
<CheckBox x:Name="restrRadioButton"/>
<TextBlock TextWrapping="Wrap" Text="bla-bla" />
<TextBox Name="AmountOfO" HorizontalAlignment="Stretch" MinWidth="70" Height="20" Margin="10,0,0,0"/>
</UniformGrid>
</Grid>
You can replace your stackpanel with a grid similar to the one shown below;
<Grid Name="AmountOfSP" Visibility="Collapsed">
<Grid.ColumnDefinitions>
<ColumnDefinition/>
<ColumnDefinition/>
<ColumnDefinition/>
</Grid.ColumnDefinitions>
<CheckBox Name="restrRadioButton" Grid.Column="0" Checked="restrCheckBox_Checked" Unchecked="restrCheckBox_Unchecked"/>
<TextBlock Grid.Column="1" TextWrapping="Wrap" Text="bla-bla" />
<TextBox Grid.Column="2" Name="AmountOfO" HorizontalAlignment="Stretch" MinWidth="70" Height="20" Margin="10,0,0,0"/>
<Grid>
You can play around with widths of your different controls by changing the columnDefinition widths e.g.
<ColumnDefinition Width="Auto"/>
As it stands all three of your columns will have the same width and will expand to fill the control it occupies.
You cannot use as stack panel in this way because it literally just gets it's width/height by "stacking" (adding) the widths/heights of the controls it contains.
You may find work-arounds using the stack panel but it is much easier just to use a different control meant to do the job you are after.

How can I layer a Polygon over a StackPanel, which is inside a ScrollViewer?

I have a horizontal ScrollViewer that contains a single StackPanel, which is initially empty. UserControls are created on button-click, and added to the StackPanel. The code looks something like this:
<ScrollViewer Grid.Column="1" Grid.Row="0" RequestedTheme="Dark" ScrollViewer.HorizontalScrollMode="Auto" ScrollViewer.HorizontalScrollBarVisibility="Auto" ScrollViewer.VerticalScrollMode="Disabled" ScrollViewer.VerticalScrollBarVisibility="Hidden">
<StackPanel x:Name="Container" HorizontalAlignment="Left" VerticalAlignment="Top" Width="Auto">
<!--User controls added here dynamically-->
</StackPanel>
</ScrollViewer>
As you can see the ScrollViewer is itself in a larger Grid. Now I would like a Polygon to be added to this ScrollViewer, but I cannot add it as a child directly, since "Content can only be set once". If I add it to the StackPanel in code-behind (after setting Canvas left, top and ZIndex), the UserControls are added below the Polygon. I want them to be under or over, either will do. Is this even possible? Right now, my Polygon shares the same Grid Row and Column as the ScrollViewer. Here is my Polygon:
<Polygon x:Name="Gripper" Grid.Column="1" Grid.Row="0" Points="0,0 0,730 -30,750 -30,800 30,800 30,750 0,730 0,100" Stroke="#DEDEDE" StrokeThickness="1" Opacity="1.0" ManipulationMode="TranslateX" ManipulationDelta="Gripper_ManipulationDelta">
<Polygon.Fill>
<SolidColorBrush Color="#FFFFFF" Opacity="0.9"/>
</Polygon.Fill>
<Polygon.RenderTransform>
<CompositeTransform />
</Polygon.RenderTransform>
</Polygon>
I am okay with adding it in XAML or C#, but I think I would prefer to do it in C# since I would like to change the points based on the size of the screen.
Put another container control between the StackPanel and the Polygon. An intermediate Grid will let you control their placement by row and column as normal. An intermediate StackPanel will let the Container stack and Polygon stack separately from the items within the Container stack:
<ScrollViewer>
<Grid>
<StackPanel x:Name="Container" HorizontalAlignment="Left" VerticalAlignment="Top" Width="Auto">
<!--User controls added here dynamically-->
</StackPanel>
<Polygon />
</Grid>
</ScrollViewer>

Fill StackPanel inside DockPanel

This should be easy: how can I stretch StackPanel inside the DockPanel, so that it would fill the whole parent's content and also maintain it's HorizontalAlignment?
Example:
<DockPanel LastChildFill="True">
<StackPanel Orientation="Horizontal" HorizontalAlignment="Center" Background="Yellow">
<Button Height="30">Button1</Button>
<Button Height="30">Button2</Button>
</StackPanel>
</DockPanel>
In this example the StackPanel's width is the same as the combined width from both buttons (and the background here is yellow), but the remaining space in DockPanel stays white. Looks like the LastChildFille property isn't working in my example.
I think by setting HorizontalAligment to Center on the StackPanel you are overriding the behavior of the DockPanel to fill the whole space with the StackPanel.
When i understand your question right, you want that the full space is yellow and the stackpanel with buttons is centered in the middle. Then you should wrap the StackPanel inside a Grid.
<DockPanel LastChildFill="True">
<Grid Background="Yellow">
<StackPanel Orientation="Horizontal" HorizontalAlignment="Center">
<Button Height="30">Button1</Button>
<Button Height="30">Button2</Button>
</StackPanel>
</Grid>
</DockPanel>

WPF Create a slide out panel

I don't know how this works technically but my requirement is as follows. I have a DataGrid and to input data into the DataGrid, I want a panel at the bottom of the DataGrid that slides out on a button click showing input options. Except, as the panel slides out, the DataGrid has to resize vertically as well. Can someone throw some light on how I can implement this?
You should be able to use a StackPanel with 2 children, your grid and your panel. Set the initial height of your panel to 0. Once the button is clicked, set the height to whatever you need it to be (e.g., MyPanel.Height = 20). You might want to wrap the grid in a ScrollViewer in case that is needed.
<StackPanel Orientation="Vertical">
<ScrollViewer Height="Auto" VerticalAlignment="Stretch">
<Grid Height="*" VerticalAlignment="Stretch" />
</ScrollViewer>
<ContentControl x:Name="MyPanel" Height="0" />
</StackPanel>
You might need to experiment with VerticalAlignment and Height="Auto" or Height="0" to get the layout you want.
You can use Expander. Please look at the following code snippet.
<DockPanel>
<Expander DockPanel.Dock="Bottom">
<StackPanel>
<TextBlock Height="25"></TextBlock>
<TextBlock Height="25"></TextBlock>
<TextBlock Height="25"></TextBlock>
</StackPanel>
</Expander>
<Border BorderBrush="LightGreen" BorderThickness="2">
<DataGrid/>
</Border>
</DockPanel >

Categories