WPF Grid with Row heights * not expanding to Grid's max height - c#

My WPF Grid has 3 rows (Auto, *, *) and maxHeight set to 500. When there is no content for second or 3rd row, Grid still doesn't expand to its maxHeight.
XAML Code:
<Grid MaxHeight="500">
<Grid.RowDefinitions>
<RowDefinition Height="Auto"/>
<RowDefinition Height="*"/>
<RowDefinition Height="*"/>
</Grid.RowDefinitions>
<!-- Button occupies 30 px-->
<Button Grid.Row="0" Content="SwitchGrid"/>
<ContentControl Grid.Row="1" Content="{Binding DG1}"/>
<ContentControl Grid.Row="2" Content="{Binding DG2}"/>
</Grid>
Problem Statement:
[Success] If both ContentControls are provided, they occupy equal space (~230 px) and Grid is shown to expand to MaxHeight=500 px.
[Failure] If either of the ContentControls are not provided, the other contentcontrol still occupies max ~230 px (this ContentControl can occupy 500 px, but due to Grid's restriction it occupies only 230 px and shows a scrollbar) and Grid doesn't expand to 500 px. Snoop reveals that one of the control control size is 0, but looks like Grid is still reserving space for it. I have seen this behavior even when the Grid is placed directly inside MainWindow, hence I dont this it is related to any other container.
What can I do to make sure Grid expands to MaxHeight if any of its children need it?
Thanks,
RDV

You can bind the row height to a string property..
<Grid MaxHeight="500">
<Grid.RowDefinitions>
<RowDefinition Height="Auto"/>
<RowDefinition Height="{Binding Row1Height, FallbackValue=*}"/>
<RowDefinition Height="{Binding Row2Height, FallbackValue=*}"/>
</Grid.RowDefinitions>
<!-- Button occupies 30 px-->
<Button Grid.Row="0" Content="SwitchGrid"/>
<ContentControl Grid.Row="1" Content="{Binding DG1}"/>
<ContentControl Grid.Row="2" Content="{Binding DG2}"/>
</Grid>
Then you can update it whenever you want, for example..
public DG1 DG1 {
set{
// ..
Row1Height = value == null ? "0" : "*";
}
get{
// ..
}
}

Related

WPF - GridRows Spacing Confusion

I have an Expander control, and the grid inside will have a ListBox with a Label on top of it saying 'Video Sources'. I am attempting to use Grid Row Definitions to achieve this. My issue however is that the grid rows separate everything evenly. I want the label to be directly on top of the ListBox. Removing the definitons causes the ListBox to fill up the entire grid including covering up the Label (which makes no sense to me as the label is on top).
My current code is below:
<Expander HorizontalAlignment="Left" Height="434" Header="Expander" ExpandDirection="Left" Margin="651,8,0,8">
<Grid Background="#FF252525" ShowGridLines="True">
<Grid.RowDefinitions>
<RowDefinition></RowDefinition>
<RowDefinition></RowDefinition>
<RowDefinition></RowDefinition>
</Grid.RowDefinitions>
<Label Content="Video Sources" Grid.Row="0"/>
<ListBox Grid.Row="1" d:ItemsSource="{d:SampleData}">
</ListBox>
</Grid>
</Expander>
The code produces this result. You can see there are even gaps between each control. I want the video sources label right above the listbox:
It would be nice if you could set the column name like in a ListView, however as far as I am aware that is not possible. I don't think it's worth using a ListView for something that will only have a single column, either
You have to set the rows height ; to auto (ie: minimal value) and * (ie: remaining space).
Also only two rows definition are needed.
<Grid>
<Grid.RowDefinitions>
<RowDefinition Height="auto" />
<RowDefinition Height="*" />
</Grid.RowDefinitions>
<Label Grid.Row="0"
Content="Video Sources" />
<ListBox Grid.Row="1"
ItemsSource="{d:SampleData}"
VerticalAlignement="Top" />
</Grid>

Ellipse position according to grid layout

I'm facing some elements' positioning problem in my wp 8.1 app (XAML/C#). I've read that to create a flexible layout, I should use the grid control.
Well, here is my XAML within the page element:
<Grid Style="{StaticResource LayoutGridCreateProfilStyle}">
<Grid.RowDefinitions>
<RowDefinition Height="Auto"/>
<RowDefinition Height="Auto"/>
<RowDefinition Height="Auto"/>
<RowDefinition Height="*"/>
</Grid.RowDefinitions>
<Rectangle Grid.Row="0" Height="60" Fill="#F3A8E4F9" ></Rectangle>
<Rectangle Grid.Row="1" Height="40" Fill="Gray"></Rectangle>
<ListBox Grid.Row="2" Height="420" Background="Transparent"/>
<Canvas Grid.Row="3">
<Ellipse Height="100" Margin="0,0,0,0" Width="100" Fill="Black" Canvas.Left="152" Canvas.Top="10"></Ellipse>
</Canvas>
</Grid>
In the XAML designer, I'm actually seeing what I want and it looks like below:
And here is how it looks like on my Nokia Lumia 925:
As you can see, the ellipse is cut and I really cannot figure out how to place it as it should be and actually appears in the designer view.
Maybe somebody could help me with that ?
Thanks in advance !
The problem is that you are running out of height to show all the elements of your grid. The first three rows take up an accumulated height of 540 pixels. If the run time height available if 640 then you only have 100 left over for the last row of your grid.
But your Ellipse is offset 10 pixels from the top of the Canvas and so it needs a total of 110 (10 offset + 100 pixel ellipse height) in order to show fully. If your last row has less than 110 pixels of space then it will be truncated, as indeed it seems to be.

How to make WPF WrapPanel height automatically grow (double) when wrap to two lines occurs

I have a grid with two rows like
<Grid.RowDefinitions>
<RowDefinition Height="44" />
<RowDefinition Height="*" />
</Grid.RowDefinitions>
<WrapPanel Grid.Row="0" HorizontalAlignment="Stretch" Orientation="Horizontal">
//...
</WrapPanel>
In the first row I am placing a WrapPanel with horizontal orientation. The elements within the WrapPanel are approx 40 heigth so it looks cool when there is only one line. However when the items wraps to two lines (say because the user decreases the width of the column with GridSplitter) then the WrapPanel correctly breaks into two line, but the second line is not shown, because the fixed 44 row height.
How can I achieve that the first row should be 44 or 88 according the WrapPanel's one line or two line layout?
Thanks in advance
It's a shame I did not figured out... "Auto" is the answer. Auto is never worked for me so maybe that's why it was not popped up in my mind first....
<Grid.RowDefinitions>
<RowDefinition Height="Auto" />
<RowDefinition Height="*" />
</Grid.RowDefinitions>
<WrapPanel Grid.Row="0" HorizontalAlignment="Stretch" Orientation="Horizontal">

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>

ListBox is contained in a ScrollViewer

I would like the ScrollViewer of the page to be displayed when all the information cannot be shown on the screen (i.e. resize the window)
However, the ListBox here doesn't get a scroll and it gets sketch till the bottom of the page unless i set it to have a MaxSize. Is there a way to give priority to the ListBox to display its ScrollViewer before the one I have made?
what i have right now
http://i.imgur.com/bEJcz.png
what i would like to achieve, but i used a MaxHeight for the ListBox here.
Here's some my markup:
<ScrollViewer HorizontalAlignment="Stretch" VerticalScrollBarVisibility="Auto" Name="scrollViewer1" VerticalAlignment="Stretch" >
<Grid>
<Grid.RowDefinitions>
<RowDefinition Height="Auto"/>
<RowDefinition Height="Auto"/>
</Grid.RowDefinitions>
<ComboBox Grid.Row="0" Width="120" HorizontalAlignment="Left"></ComboBox>
<ListBox HorizontalAlignment="Left" Name="listBox" Width="120" Grid.Row="1" <!--MaxHeight="500"--> />
</Grid>
</ScrollViewer>
I know this question is old, but I had exactly the same problem and came up with a bit of a hack as a fix but its better than having the question unsolved.
Much of what I've read states that using things like StackPanel is bad in this case because the panel grows to fit the elements it holds. Normally this works fine because you can stick the StackPanel into a Grid and set the MinHeight and MaxHeight of the column/row and lock the controls in place. As soon as the ScrollView is added this kind of goes to hell. The answer above describes the problem well, but lacks a solution.
I tried many different types of Panels instead of a StackPanel but they all yield the same result. I decided that since my ListBox sits inside of a Grid, I needed to bind the MaxHeight of that grid location to some other value in the control to keep the ListBox from growing. The problem with this is that there is no element that you can bind straight to and get the exact height your looking for.
Enter the hack:
My height was just a tiny bit too big creating a weird always offscreen ListBox (in fact 36 pixels too large, which was the height of the label above the ListBox). So I implemented the IValueConverter:
class HeightToAdjustedHeightConverter : IValueConverter
{
public object Convert(object value, Type targetType, object parameter, CultureInfo culture)
{
var height = (double) value - 33d;
return height < 360d ? 360d : height;
//360 being the minimum height allowed for the listbox
}
public object ConvertBack(object value, Type targetType, object parameter, CultureInfo culture)
{
return null;
}
}
All I did after that was include it as a converter for the binding on MaxHeight (Note you need to name your usercontrol and bind to its x:Name):
<Grid Grid.Column="0"
Grid.Row="1"
VerticalAlignment="Top"
ClipToBounds="True"
MaxHeight="{Binding ElementName=AdHocUserControl, Path=ActualHeight, Converter={StaticResource HeightToAdjustedHeightConverter}}">
The only other alternative I can think of is to extend one of the panels and try to play with its growth behavior. I admit this is a hack, but it will work.
Try this
<ScrollViewer HorizontalAlignment="Stretch" VerticalScrollBarVisibility="Auto" Name="scrollViewer1" VerticalAlignment="Stretch" >
<Grid>
<Grid.RowDefinitions>
<RowDefinition Height="Auto"/>
<RowDefinition Height="*"/>
</Grid.RowDefinitions>
<ComboBox Grid.Row="0" Width="120" HorizontalAlignment="Left" ></ComboBox>
<ListBox HorizontalAlignment="Left" Name="listBox" Width="120" VerticalAllignment = "Top" Grid.Row="1"/>
</Grid>
</ScrollViewer>
Or you can also try this
<Grid >
<Grid.RowDefinitions>
<RowDefinition Height="Auto"/>
<RowDefinition Height="*"/>
</Grid.RowDefinitions>
<ComboBox Grid.Row="0" Width="120" HorizontalAlignment="Left" ></ComboBox>
<ListBox HorizontalAlignment="Left" Name="listBox" VerticalAlignment= "Top" Width="120" Grid.Row="1" ScrollViewer.VerticalScrollBarVisibility="Auto"/>
</Grid>
You have a logical inconsistency in your definitions.
The requirement as you put it: "I would like the scrollviewer of the page to be displayed when all the information cannot be shown on the screen [without using MaxHeight]" - a question arises: "How do you determine that 'all the information cannot be shown on the screen'?" or "At what point the ListBox should stop growing and show the scroll bar?".
From a WPF\Silverlight layout management logic, it does exactly what you want - when the sum of height of list box plus the height of the combo box is greater than the ViewportHeight of the scroll viewer - you get a scroll bar. That is possible only when you allow the ListBox to grow to it's desired size without scroll bars.
Dont set the MaxHeight on the ListBox, just use the star '*' notation in your RowDefinitions to get the relative sizing between your 2 controls correct.
Another solution:
<ScrollViewer HorizontalAlignment="Stretch" VerticalScrollBarVisibility="Auto" Name="scrollViewer1" VerticalAlignment="Stretch" >
<Grid>
<Grid.RowDefinitions>
<RowDefinition Height="Auto"/>
<RowDefinition Height="*"/>
</Grid.RowDefinitions>
<ComboBox Grid.Row="0" Width="120" HorizontalAlignment="Left"></ComboBox>
<ScrollViewer x:Name="scrollViewer" Grid.Row="1" ScrollViewer.VerticalScrollBarVisibility="Disabled" >
<ListBox HorizontalAlignment="Left" Name="listBox" Width="120" Grid.Row="1" MaxHeight="{Binding ActualHeight, ElementName=scrollViewer}" ScrollViewer.VerticalScrollBarVisibility="Auto"/>
</ScrollViewer>
</Grid>

Categories