WPF layout issue with nested StackPanel straying outside parent StackPanel - wpf

I have a horizontal StackPanel with an image and another StackPanel. The inner StackPanel is vertical with two TextBlocks both of which have TextWrapping set to Wrap. However when the text gets wide the inner StackPanel increases in width so that the TextBlocks don't wrap. The outer StackPanel is staying with the grid layout space it has been given. How can I make the inner StackPanel stay within the bounds of the outer StackPanel?
Here's the relevant section of XAML:
<StackPanel Name="_imageAndNameStackPanel"
Grid.Row="0" Grid.Column="0" Grid.ColumnSpan="3"
Orientation="Horizontal" Margin="12,12,12,0">
<Image Name="_applicationImage" Source="{Binding Path=ImageUri}"
Stretch="Fill" Height="64" Width="64" HorizontalAlignment="Left"
VerticalAlignment="Top" Margin="0,0,12,0" />
<StackPanel Name="_nameStackPanel">
<TextBlock Name="_nameTextBlock" Text="{Binding Path=AppName}"
FontSize="24" VerticalAlignment="Top" TextWrapping="Wrap"/>
<TextBlock Name="_subtitleTextBlock" Text="{Binding Path=Subtitle"
FontSize="18" VerticalAlignment="Top" Margin="0,6,0,0"
TextWrapping="Wrap"/>
</StackPanel>
</StackPanel>

You're probably better off with a DockPanel instead of StackPanel.
<StackPanel Name="_imageAndNameStackPanel"
Grid.Row="0" Grid.Column="0" Grid.ColumnSpan="3"
Orientation="Horizontal" Margin="12,12,12,0">
<Image Name="_applicationImage" Source="{Binding Path=ImageUri}"
Stretch="Fill" Height="64" Width="64" HorizontalAlignment="Left"
VerticalAlignment="Top" Margin="0,0,12,0" />
<DockPanel Name="_nameStackPanel">
<TextBlock Name="_nameTextBlock" Text="{Binding Path=AppName}"
FontSize="24" VerticalAlignment="Top" TextWrapping="Wrap"
DockPanel.Dock="Top" />
<TextBlock Name="_subtitleTextBlock" Text="{Binding Path=Subtitle"
FontSize="18" VerticalAlignment="Top" Margin="0,6,0,0"
TextWrapping="Wrap" DockPanel.Dock="Top"/>
</DockPanel>
</StackPanel>
Lately I'm finding that 2 out of 3 times that I start with StackPanel I end up changing it to DockPanel.
But… are you sure that the outer StackPanel is not expanding beyond the bounds of its grid cell? You might want to make that one a DockPanel as well, with both the Image and the inner DockPanel having DockPanel.Dock="Left".

You could bind your inner StackPanel's width to the Parent StackPanel's width. Something like:
{Binding RelativeSource={RelativeSource AncestorType={x:Type StackPanel}}, Path=Width}

Give your inner stackpanel or textblock's a fixed width.

Related

cannot display the slider of a scrollviewer

I can't get the slider for a scrollviewer to display. I have a listbox in a wrappanel. The listbox has a list of numbers. The list can be long enough to extend off of the bottom of the screen, so a scrollviewer is needed, but no matter how I set scrollviewer properties, or even if I put the listbox inside a scrollviewer inside the wrappanel, the slider doesn't appear. What am I doing wrong? Here's the XAML:
<WrapPanel Grid.Row="5" Grid.ColumnSpan="2">
<ListBox x:Name="lstBxCollisions"
HorizontalAlignment="Left" VerticalAlignment="Top"
Height="auto" Width="auto"
ItemsSource="{Binding MainWindow.lstBxCollisions}"
ScrollViewer.VerticalScrollBarVisibility="Auto"/>
<FlowDocumentReader Grid.Row="5" Grid.Column="1" Document="{Binding SingleAccidentFlowDocument}">
</FlowDocumentReader>
</WrapPanel>
Since your ListBox is inside WrapPanel, all its sizes are selected automatically and it begins to expand as the content size increases.
If you want it to appear ScrollBar, you need to fix the size of the ListBox by setting the actual height and width.
For example:
<WrapPanel Grid.Row="5" Grid.ColumnSpan="2">
<ListBox x:Name="lstBxCollisions"
HorizontalAlignment="Left" VerticalAlignment="Top"
Height="100" Width="100"
ItemsSource="{Binding MainWindow.lstBxCollisions}"
ScrollViewer.VerticalScrollBarVisibility="Auto"/>
<FlowDocumentReader Grid.Row="5" Grid.Column="1" Document="{Binding SingleAccidentFlowDocument}">
</FlowDocumentReader>
</WrapPanel>

Left and right alignment leaving space in the middle inside StackPanel

I have this user control:
And I want to achieve this result:
The XAML of the bottom part is like this:
<StackPanel HorizontalAlignment="left" Orientation="Horizontal">
<TextBox materialDesign:HintAssist.Hint="Filtrar por patente" Width="auto" Margin="5" Text="{Binding Filtro, Mode=TwoWay,UpdateSourceTrigger=PropertyChanged}" HorizontalAlignment="Left"></TextBox>
<Button Width="120" Style="{DynamicResource MaterialDesignRaisedButton}" Margin="5" HorizontalAlignment="Right" Command="{x:Static materialDesign:DialogHost.CloseDialogCommand}">Volver</Button>
</StackPanel>
I cannot find a way to align textbox to the left and button to the right, leaving a dynamic space in the middle. Button should have fixed width and textbox should be auto.
Thanks
Use a DockPanel. You'll want to stretch it instead of aligning it to the left.
<DockPanel
HorizontalAlignment="Stretch"
>
<TextBox
DockPanel.Dock="Left"
materialDesign:HintAssist.Hint="Filtrar por patente"
Width="auto"
Margin="5"
Text="{Binding Filtro, UpdateSourceTrigger=PropertyChanged}"
HorizontalAlignment="Left"
/>
<Button
DockPanel.Dock="Right"
Width="120"
Style="{DynamicResource MaterialDesignRaisedButton}"
Margin="5"
HorizontalAlignment="Right"
Command="{x:Static materialDesign:DialogHost.CloseDialogCommand}"
>Volver</Button>
</DockPanel>

Stretch items to fill canvas

I have a Dockpanel with items inside a Canvas. The Dockpanel and any other items (Grid etc) that I place inside the Canvas, only take up their minimum required space. How do I stretch these items to fill the entire Canvas?
<Canvas x:Name="InfoCanvas" VerticalAlignment="Stretch" HorizontalAlignment="Stretch" Margin="72,53,0,0">
<DockPanel VerticalAlignment="Stretch" HorizontalAlignment="Stretch" Margin="0,0,0,0" x:Name="ReferenceInfo" Canvas.Left="0" Canvas.Top="0">
<TextBox x:Name="ReferenceAuthor" GotFocus="FieldEnter" LostFocus="FieldLeave" FontSize="16" FontFamily="Segoe UI Light" Text="Author" Foreground="Gray" Background="Transparent" DockPanel.Dock="Top" VerticalAlignment="Top" HorizontalAlignment="Stretch" BorderThickness="0" Margin="0,2,0,2"/>
<TextBox x:Name="ReferenceTitle" GotFocus="FieldEnter" LostFocus="FieldLeave" FontSize="16" FontFamily="Segoe UI Light" Text="Title" Foreground="Gray" Background="Transparent" DockPanel.Dock="Top" VerticalAlignment="Top" HorizontalAlignment="Stretch" BorderThickness="0" Margin="0,2,0,2"/>
<TextBox x:Name="ReferenceDate" GotFocus="FieldEnter" LostFocus="FieldLeave" FontSize="16" FontFamily="Segoe UI Light" Text="Date" Foreground="Gray" Background="Transparent" DockPanel.Dock="Top" VerticalAlignment="Top" HorizontalAlignment="Stretch" BorderThickness="0" Margin="0,2,0,2"/>
</DockPanel>
</Canvas>
Thank you!
The Canvas panel doesn't really support that.
It's very basic - it just allows you to position children absolutely by using Top, Bottom, Left and Right, and it always gives them just the space they need.
So usually you would use a Grid with just 1 column and 1 row instead.
You can however bind the width and height of the DockPanel to the width and height of the Canvas. That way the DockPanel will always fill the Canvas.
<DockPanel VerticalAlignment="Stretch" HorizontalAlignment="Stretch"
Margin="0,0,0,0" x:Name="ReferenceInfo" Canvas.Left="0" Canvas.Top="0"
Width="{Binding ActualWidth, ElementName=InfoCanvas}"
Height="{Binding ActualHeight, ElementName=InfoCanvas}">
What you can do is:
<Grid>
<Canvas x:Name="InfoCanvas">
<!--Elements with canvas layout here-->
</Canvas>
<DockPanel x:Name="ReferenceInfo">
<!--Elements with dockpanel layout here-->
</DockPanel>
</Grid>
By wrapping both panels in a grid like this you can place elements that you cant to position relative to left, top etc in the canvas. Both the canvas and the dockpanel will fill available space. Note that the elements in the dockpanel will be rendered above the elements in the canvas when the dockpanel is defined after in xaml.
I'm assuming the code you posted is pseudo code, if not you should just remove the canvas.

Why won't the WPF progressbar stretch to fit?

This is my original code:
<StackPanel Grid.Row="3" Grid.Column="0" Grid.ColumnSpan="2" Orientation="Horizontal">
<ProgressBar Height="23" Name="searchProgressBar" Foreground="Blue" BorderBrush="#00000000" BorderThickness="1" VerticalAlignment="Top" HorizontalAlignment="Stretch"/>
<TextBlock Text="asdf" Height="23" Name="progressTextBlock" VerticalAlignment="Top" Foreground="Red" HorizontalAlignment="Right"/>
</StackPanel>
The progressbar was very small, maybe 2 or 3 pixels wide, then there was the text block and empty space after. So I tried explicitly docking the elements to sides:
<DockPanel Grid.Row="3" Grid.Column="0" Grid.ColumnSpan="2" >
<ProgressBar DockPanel.Dock="Left" Height="23" Name="searchProgressBar" Foreground="Blue" BorderBrush="#00000000" BorderThickness="1" VerticalAlignment="Top" />
<TextBlock DockPanel.Dock="Right" Text="asdf" Height="23" Name="progressTextBlock" VerticalAlignment="Top" Foreground="Red" HorizontalAlignment="Right"/>
</DockPanel>
No avail. I also tried modifying each solution by setting HorizontalAlignment="Stretch" on the progress bar, but there's no change. How do i stretch it to fill all the space there is after the text block has been rendered?
Remove DockPanel.Dock="Left" from the ProgressBar and switch the order of the controls:
<DockPanel>
<TextBlock DockPanel.Dock="Right" Height="23" VerticalAlignment="Top" HorizontalAlignment="Right"/>
<ProgressBar Height="23" VerticalAlignment="Top" />
</DockPanel>
By default, DockPanel has its property LastChildFill set to true, which will make the ProgressBar take the available space.
ahh I see what you're trying to do. This is probably a better place to use a grid with 2 column definitions. The first(the left one) columndefinition with Width="*" and the second(the right one) with a width set to Width="Auto". For more info about auto vs * see http://social.msdn.microsoft.com/Forums/en-US/wpf/thread/9a7e6591-1fae-4295-b68a-be97e8e53d06/

Width of child control should match width of parent container

I'm pretty new to WPF. I often find my self struggling with getting a bunch of child controls combined width to match a given parent container.. As in the following:
<ListBox x:Name="BrugereListBox" Grid.Column="0" Grid.Row="3" DataContext="{DynamicResource Brugere}"
ItemsSource="{Binding}"
PreviewMouseLeftButtonDown="BrugereListBox_MouseLeftButtonDown"
PreviewMouseMove="BrugereListBox_PreviewMouseMove"
>
<ListBox.ItemTemplate >
<DataTemplate >
<Border BorderBrush="Black" BorderThickness="1" Margin="2">
<StackPanel Orientation="Vertical" IsEnabled="True"
PreviewMouseLeftButtonDown="StackPanel_PreviewMouseLeftButtonDown">
<StackPanel Orientation="Horizontal" >
<Label>Navn</Label>
<TextBox Text="{Binding Name}"></TextBox>
</StackPanel>
<StackPanel Orientation="Horizontal">
<Label>Password</Label>
<TextBox Text="{Binding Password}"></TextBox>
</StackPanel>
<StackPanel Orientation="Horizontal">
<Label>Email</Label>
<TextBox Text="{Binding Email}"></TextBox>
</StackPanel>
</StackPanel>
</Border>
</DataTemplate>
</ListBox.ItemTemplate>
</ListBox>
In this case I'm interested in getting the width of the children of the stackpanel:
<StackPanel Orientation="Horizontal" >
<Label>Navn</Label>
<TextBox Text="{Binding Name}"></TextBox>
</StackPanel>
to match the width of
<ListBox x:Name="BrugereListBox"
Any generic solution to scenarios like this?
turns out to be a dupe of:
wpf border control to span the width of listboxItem
and the answer given there:
This is probably more to do with the
ListBoxItems themselves not taking up
the full width of the ListBox. Add the
HorizontalContentAlignment="Stretch"
attribute to your ListBox and see if
it stretches the individual items to
fill the width.
so change to:
<ListBox x:Name="BrugereListBox" Grid.Column="0" Grid.Row="3" DataContext="{DynamicResource Brugere}"
ItemsSource="{Binding}"
PreviewMouseLeftButtonDown="BrugereListBox_MouseLeftButtonDown"
PreviewMouseMove="BrugereListBox_PreviewMouseMove"
HorizontalContentAlignment="Stretch"
>
but as Kent says, using a Grid would be better in my opinion.
Use the right panel and you'll be fine. StackPanel makes its own decisions about its width/height depending on its orientation and its children. Use a Grid and it will just take up the space it is given - no more, no less.

Resources