Trouble with Grid and StackPanel - Bindings - c#

OK, I'm having issues properly using a ScrollViewer (containing an ItemsControl) inside a StackPanel.
The thing is the scrolling works, however :
No matter how much the user scrolls down, the bottom lines of the tables are not visible
When scrolling is... "released", the table pops back up...
<ScrollViewer Height="Auto">
<ItemsControl ItemsSource="{Binding Items, Mode=TwoWay}">
<ItemsControl.ItemTemplate>
<DataTemplate>
<Grid VerticalAlignment="Top" Margin="0,0,0,0" x:Name="ResTable">
<Grid.ColumnDefinitions>
<ColumnDefinition Width="0.10*"/>
<ColumnDefinition Width="0.30*" />
<ColumnDefinition Width="0.30*"/>
<ColumnDefinition Width="0.30*"/>
</Grid.ColumnDefinitions>
<Grid.RowDefinitions>
<RowDefinition Height="*"/>
<RowDefinition Height="Auto"/>
</Grid.RowDefinitions>
<TextBlock Grid.Column="0" Text="{Binding [num]}" HorizontalAlignment="Center" />
<TextBlock Grid.Column="1" Text="{Binding [A]}" HorizontalAlignment="Center" />
<TextBlock Grid.Column="2" Text="{Binding [B]}" HorizontalAlignment="Center" />
<TextBlock Grid.Column="3" Text="{Binding [C]}" HorizontalAlignment="Center" />
</Grid>
</DataTemplate>
</ItemsControl.ItemTemplate>
</ItemsControl>
</ScrollViewer>
Any ideas?
P.S.
I've had a look at some of the other answers to similar issues, but none seems to be working...
My main idea is to display a table, with a fixed header, and scrollable contents (populated via Bindings) - ok, and there are also a couple of things on the top of the page (apart from the table I mean)

I guess the issue is that you should probably use parent element like Grid, not StackPanel, because StackPanel has its drawbacks when resizing child items with scrolls and so on.
<Grid>
<Grid.RowDefinitions>
<RowDefinition Height="Auto"/>
<RowDefinition Height="*"/>
</Grid.RowDefinitions>
<!-- Put headers in Grid.Row="0" -->
<!-- Put Scrollviewer in Grid.Row="1" -->
</Grid>
Also Height="Auto" attribute can be removed from ScrollViewer, you might want to use VerticalAlignment="Stretch" for item to take all the available space. I hope this is what you are trying to achieve.

Related

WPF how to get control and TextBlock to align in center in stretched grid

I have the following scenario:
<Grid x:Uid="Grid_3" Grid.Row="0" Margin="5" Focusable="False" Visibility="Visible" Background="DarkGray" Opacity="0.4" VerticalAlignment="Stretch" HorizontalAlignment="Stretch">
<Grid.RowDefinitions>
<RowDefinition x:Uid="RowDefinition_8" Height="Auto"/>
<RowDefinition x:Uid="RowDefinition_9" Height="Auto"/>
</Grid.RowDefinitions>
<controls:LoadingPanel Grid.Row="0" IsLoading="True"
HorizontalLoadingIndicatorAlignment="Center"
VerticalLoadingIndicatorAlignment="Center"
/>
<TextBlock x:Uid="TextBlock_4" Grid.Row="1" HorizontalAlignment="Center" VerticalAlignment="Center" Text="Commit In Process..." />
</Grid>
</Grid>
I want the LoadingPanel and the TextBlock to be aligned in the center of the Grid which I have set to be stretched vertically and horizontally.
Note that the grid is already inside another grid. At the moment both places themselves at the top.
So, I'm guessing the issue you're seeing is that the controls are not centred vertically but instead sit at the top of the grid?
To resolve this (while keeping the controls below one another) simply add a relative sized row above and below the two rows for the controls like so:
<Grid x:Uid="Grid_3" Grid.Row="0" Margin="5" Focusable="False" Visibility="Visible" Background="DarkGray" Opacity="0.4" VerticalAlignment="Stretch" HorizontalAlignment="Stretch">
<Grid.RowDefinitions>
<RowDefinition Height="0.5*"/>
<RowDefinition x:Uid="RowDefinition_8" Height="Auto"/>
<RowDefinition x:Uid="RowDefinition_9" Height="Auto"/>
<RowDefinition Height="0.5*"/>
</Grid.RowDefinitions>
<controls:LoadingPanel Grid.Row="1" IsLoading="True"
HorizontalLoadingIndicatorAlignment="Center"
VerticalLoadingIndicatorAlignment="Center"
/>
<TextBlock x:Uid="TextBlock_4" Grid.Row="2" HorizontalAlignment="Center" VerticalAlignment="Center" Text="Commit In Process..." />
</Grid>
This should sort out the issue.
Just to be able to give an answer to this topic, I am reposting the comment from above, to allow #DSF to accept it.
Apparently the issue was related to the fact that the grid had two rows, and each control was on it`s own row. Discarding the rows solved his issue.
To fix the order of visibility, as you want, use Panel.ZIndex="2" on the LoadingPanel and Panel.ZIndex="1" on the TextBlock, like this

How to structure a stacked form with WPF XAML?

On my Window, I've got a GroupBox. I'd like to build out a horizontally aligned form inside of that GroupBox. By horizontally aligned, I mean a form where the label and the input reside on the same grid row or x axis. Separate form labels + inputs reside on their own row.
Since a GroupBox can only have one child content, I assume I need to either use a Grid or StackPanel. I'm trying to use a StackPanel because that seems simpler and should achieve what I'm aiming for.
The issue I'm trying to figure out is how to group the input and label into one unit so they can reside horizontally next to each other, but stack vertically as a pair within the StackPanel.
It's probably best to use a Grid that way you an get the labels and inputs to line up vertically. While it's not impossible with a stack panel it's a whole lot harder. If you set the grid's RowDefinition heights to "Auto" the grid will only be as tall as it needs to be:
<GroupBox>
<Grid>
<Grid.ColumnDefinitions>
<ColumnDefinition Width="Auto"/>
<ColumnDefinition Width="*"/>
</Grid.ColumnDefinitions>
<Grid.RowDefinitions>
<RowDefinition Height="Auto"/>
<RowDefinition Height="Auto"/>
<RowDefinition Height="Auto"/>
</Grid.RowDefinitions>
<TextBlock Grid.Row="0" Grid.Column="0" Text="Label1"/>
<TextBox Grid.Row="0" Grid.Column="1" Text="{Binding Input1}"/>
<TextBlock Grid.Row="1" Grid.Column="0" Text="Label2"/>
<TextBox Grid.Row="1" Grid.Column="1" Text="{Binding Input2}"/>
etc.
</Grid>
</GroupBox>
You'll probably need to play around with margins and/or padding and horizontal alignments to get the layout exactly how you want it, but this should give you the control you need to achieve what you want.
you can use a stackpanel with orientation equal to vertical inside your groupbox and inside that stackpanel you can have another stackpanel with orientation equal to horizantal for your label and input just like following sample code.
<GroupBox Header="Sample GroupBox">
<StackPanel Orientation="Vertical">
<StackPanel Name="input1" Orientation="Horizontal">
<Label Content="input1"/>
<TextBox/>
</StackPanel>
<StackPanel Name="input2" Orientation="Horizontal">
<Label Content="input2"/>
<TextBox/>
</StackPanel>
<StackPanel Name="input3" Orientation="Horizontal">
<Label Content="input3"/>
<TextBox/>
</StackPanel>
</StackPanel>
</GroupBox>
One feature you might find useful is grid shared size scope. It can help you align elements in multiple different Grids, by sharing their column\row sizes, like this:
<GroupBox Header="Sample GroupBox">
<StackPanel Orientation="Vertical" Grid.IsSharedSizeScope="True">
<Grid>
<Grid.ColumnDefinitions>
<ColumnDefinition Width="Auto" SharedSizeGroup="firstGroup" />
<ColumnDefinition Width="Auto" SharedSizeGroup="secondGroup" />
</Grid.ColumnDefinitions>
<Label Content="input11" Grid.Column="0" />
<TextBox Grid.Column="1" Width="100"/>
</Grid>
<Grid>
<Grid.ColumnDefinitions>
<ColumnDefinition Width="Auto" SharedSizeGroup="firstGroup" />
<ColumnDefinition Width="Auto" SharedSizeGroup="secondGroup" />
</Grid.ColumnDefinitions>
<Label Content="input2222222" Grid.Column="0" />
<TextBox Grid.Column="1"/>
</Grid>
<Grid>
<Grid.ColumnDefinitions>
<ColumnDefinition Width="Auto" SharedSizeGroup="firstGroup" />
<ColumnDefinition Width="Auto" SharedSizeGroup="secondGroup" />
</Grid.ColumnDefinitions>
<Label Content="input3333333333333" Grid.Column="0" />
<TextBox Grid.Column="1"/>
</Grid>
</StackPanel>
</GroupBox>
I don't say that it is necessary in the code above, but that is just example. Often, you want to use grid in for example ItemTemplate of ItemsControl, and you want all items to be aligned. Here shared size scope might help.

WPF Expander - Horizontal Alignment set to Right, but jumps to left on when expanded

I've got a WPF Expander that is right aligned. That bit shows correctly on the screen, but when you expand it the expander and the text "show/hide historic data" jumps to the left of the screen. Close the expander and it returns to the correct (right) alignment.
I've tried various approaches but am unable to find why this is happening or more importantly how to keep an expanded expander right aligned
<Grid Grid.Row="1"
HorizontalAlignment="Stretch">
<Grid.RowDefinitions>
<RowDefinition Height="auto"/>
<RowDefinition Height="auto"/>
</Grid.RowDefinitions>
<Grid.ColumnDefinitions>
<ColumnDefinition Width="*" />
</Grid.ColumnDefinitions>
<StackPanel Grid.Row="0" >
<TextBlock Style="{StaticResource SubHeader}" Text="Historic Data Sets" />
<Rectangle Style="{StaticResource HeaderLine}"/>
</StackPanel>
<Expander Header="show/hide historic data"
Grid.Column="1"
IsEnabled="True"
VerticalAlignment="Center"
HorizontalAlignment="Right"
ExpandDirection="Down">
<!-- some other stuff in the second row such as grid... -->
</Expander>
YOu can take control of the Header by explictly marking it as a TextBlock and then change itÅ› HorizontalAlignment property:
<Expander.Header>
<TextBlock
Width="200"
HorizontalAlignment="Right"
Text="Show information.."></TextBlock>
</Expander.Header>

C# Change backgroundcolor specific row

I've created a new project from the Grid App (XAML) template (C# Windows Store).
So far I've changed nothing in the template, but I would like to change the backgroundcolor from a specific row in the grid.
<!--
This grid acts as a root panel for the page that defines two rows:
* Row 0 contains the back button and page title
* Row 1 contains the rest of the page layout
-->
<Grid Style="{StaticResource LayoutRootStyle}">
<Grid.RowDefinitions>
<RowDefinition Height="140"/>
<RowDefinition Height="*"/>
</Grid.RowDefinitions>
I would like to change the backgroundcolor from row 0 (which contains the page title).
Any ideas?? Thanks in advance!
This row consits of:
<!-- Back button and page title -->
<Grid>
<Grid.ColumnDefinitions>
<ColumnDefinition Width="Auto"/>
<ColumnDefinition Width="*"/>
</Grid.ColumnDefinitions>
<Button x:Name="backButton" Click="GoBack" IsEnabled="{Binding Frame.CanGoBack, ElementName=pageRoot}" Style="{StaticResource BackButtonStyle}"/>
<TextBlock x:Name="pageTitle" Text="{StaticResource AppName}" Grid.Column="1" IsHitTestVisible="false" Style="{StaticResource PageHeaderTextStyle}"/>
</Grid>
You can't set the background color on the Grid.Row itself, instead set the Background property on whatever occupies this row.
For example
<Grid Style="{StaticResource LayoutRootStyle}">
<Grid.RowDefinitions>
<RowDefinition Height="140"/>
<RowDefinition Height="*"/>
</Grid.RowDefinitions>
<Grid Background="Red" Grid.Row="0">
<TextBlock>Test</TextBlock>
</Grid>
</Grid>
EDIT:
Updated for Silverlight; TextBlock doesn't have Background so you have to put the control in another Border or grid container which does have background. Code updated to reflect this.
How about inserting border where you need it
<Grid Style="{StaticResource LayoutRootStyle}">
<Grid.RowDefinitions>
<RowDefinition Height="140"/>
<RowDefinition Height="*"/>
</Grid.RowDefinitions>
<Border Background="Red" Grid.ColumnSpan="1"></Border>
<TextBlock>Test</TextBlock>
<Border Background="blue" Grid.Row="1" Grid.ColumnSpan="1"></Border>
<TextBlock Grid.Row="1">Test2</TextBlock>
</Grid>
note that you can especify the columns span in case of include more columns

understanding WPF Layout

I got a ListView (wrapped in a ScrollViewer), which resizes itself if the elements inseretd exceed the visible area until the parents Max Height is reached.
The ListView is embedded the following way.
<Window ... SizeToContent="Height">
<Grid>
<Grid.RowDefinitions>
<RowDefinition Height="2*"/>
<RowDefinition Height="*" />
<RowDefinition Height="*" />
</Grid.RowDefinitions>
<Grid.ColumnDefinitions>
<ColumnDefinition Width="3*" />
<ColumnDefinition Width="2*" />
</Grid.ColumnDefinitions>
<ScrollViewer x:Name="MyScrollViewer" Grid.Row="0" Grid.Column="0" HorizontalAlignment="Stretch" VerticalAlignment="Stretch">
<ListView Name="MyListView"
ItemsSource="{Binding Path=RetrievalStringResults, Mode=OneWay}"
IsSynchronizedWithCurrentItem="True" />
</ScrollViewer>
<DockPanel Grid.Row="0" Grid.Column="1">
...
</DockPanel>
<Expander Grid.Row="1" Grid.ColumnSpan="2">
<DockPanel Height="150" HorizontalAlignment="Stretch">
<TextBox DockPanel.Dock="Top" />
</DockPanel>
</Expander>
<DockPanel Grid.Row="2" Grid.ColumnSpan="2">
... some buttons
</DockPanel>
</Grid>
</Window>
I used SizeToContent because I got a text box on the bottom wrapped in an Expander, which shall expanded on demand, and actually therefore my main window needs to resize. This actually works fine.
The problem is though the ListView's Height isn't the max height on start-up wherefore I got that "auto-resize" effect.
How can I set the ListView's hight to the max of the parents height to avoid this effect?
Another, more general issue. I think avoiding static layout parameters (static values for hight/width) is nice, but I got the feeling I'm loosing some control over my UI controls.
I recognized, resizeing my main window manually in height, it "jumps" by the 150 height of the DockPanel wrapped by the Expander on the bottom, anyway to avoid this?
What is the best pratice in dynamic UI Layout? I explored DockPanel beeing more dynamically in sizing to the surounding contorls than a StackPanel. But I guess thats not everything.
I think your issue is with your Grid definitions
<Grid>
<Grid.RowDefinitions>
<RowDefinition Height="2*"/>
<RowDefinition Height="*" />
<RowDefinition Height="*" />
</Grid.RowDefinitions>
...
</Grid>
This means that the top row is going to be twice the size of rows 2 and 3, so the top row will only take up 50% of your space while your bottom two rows each take up 25% space.
If you want the top row to take up all available space, make sure it is the only * size row, and set the other rows to Auto so they will take up whatever space they need.
<Grid>
<Grid.RowDefinitions>
<RowDefinition Height="*"/>
<RowDefinition Height="Auto" />
<RowDefinition Height="Auto" />
</Grid.RowDefinitions>
...
</Grid>

Categories