WPF resize issues when using RowDefinition Height="*" in Grid - wpf

UPDATE I added the UserControl definition to the XAML.
I've noticed some strange behavior in a couple of WPF applications I've created lately, that seem to be related to using "*" for a Grid row height or column width.
The behavior I'm referring to is when trying to expand items in a control (like a treeview), the entire window will resize its height instead of creating a scrollbar. So if I just run the application, and start expanding nodes, when the items extend beyond the visible portion of the UI then the window will resize.
BUT if I resize the window first, or even just click on the bottom or right border (without actually resizing), then it will behave normally and leave the window height alone, with a scrollbar on the treeview.
<UserControl x:Class="ProjectZ.Views.GenericDefinitionView"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
xmlns:cal="http://www.caliburnproject.org"
xmlns:xctk="http://schemas.xceed.com/wpf/xaml/toolkit"
xmlns:xcad="http://schemas.xceed.com/wpf/xaml/avalondock"
xmlns:local="clr-namespace:ProjectZ"
xmlns:behaviors="clr-namespace:ProjectZ.Behaviors"
mc:Ignorable="d" d:DesignHeight="600" d:DesignWidth="600">
<Grid>
<Grid.RowDefinitions>
<RowDefinition Height="20" />
<RowDefinition Height="*" />
</Grid.RowDefinitions>
<Menu Grid.Row="0" Name="mnuMainMenu" IsMainMenu="True">
... menu stuff
</Menu>
<xcad:DockingManager ... />
</Grid>
</UserControl>
I've played around with it and it seems to always start happening after I've used the "*" value for a grid row height or a column width. If I take that out, it seems to behave normally.
Has anyone else run into this? Any ideas what I'm doing wrong or could do differently to fix this? The only other information I think might be relevant is that this is using Caliburn.Micro. The only settings passed to the window when launching are: MinHeight, MinWidth, Title, and Icon.

The problem is that you never specify a height in the visual tree above the element.
Your UserControl or the Window that's created needs a specific height if you want to use star sizing effectively. Otherwise, a height is "chosen" at runtime, but the Window is effectively set to size by content. As you change items, the Window resizes.
As soon as you touch a border, the Height is being set (whether or not you resize), in which case it then dictates the layout correctly.
If you specify a default height for the Window as its created, the issue will likely resolve itself.

The resizing must be caused by the code:
<UserControl
//...stuff>
<Grid>
<Grid.RowDefinitions>
<RowDefinition Height="*" />
</Grid.RowDefinitions>
</Grid>
</UserControl>
Where the < * > can be understood as "Take the rest of all available space, after placing all the other elements first". So when you add another element in the control the view will set itself and the the
<RowDefinition Height="*" />
Will resize itself acordingly to take the remainder of space available. To remove this you can just set a specific height for the row or another idea will be to add another Grid inside the row definition so that it won't resize since it will always be inside the row, but still have all of it's functionality.

Related

WPF control alignment is wrong when dynamically added

Hi I thought I could solve this easily but it is driving me crazy.
I am using a UserControl to house a video player control based on VLC, along with play and stop buttons etc. I then place the UserControl on my main form. if the UserControl is declared in XAML it behaves normally.
I decided to rewrite the code to instantiate my UserControl dynamically, in case I need to destroy it and create another on the fly. But when I do the video moves to the top of its container instead of the middle.
The UserControl relevant section is here:
<Grid x:Name="LayoutParent" >
<Grid.RowDefinitions>
<RowDefinition Height="*" />
<RowDefinition Height="Auto" />
<RowDefinition Height="12" />
</Grid.RowDefinitions>
<!-- I comment this if adding player dynamically -->
<!--<wpf:VlcPlayer Grid.Row="0" x:Name="Player" />-->
<!-- I un-comment this if adding player dynamically -->
<Grid x:Name="VideoPlayerPanel" Grid.Row="0" Margin="0" />
<StackPanel Grid.Row="1" Opacity="0.8">
...(buttons etc)
</StackPanel>
<ProgressBar ...(progressBar etc) />
</Grid>
My codebehind looks like this:
Dim Player As VlcPlayer = New VlcPlayer ' uncomment If adding the player dynamically
Public Sub New()
' This call is required by the designer.
InitializeComponent()
' Add any initialization after the InitializeComponent() call.
Player.SetValue(Canvas.ZIndexProperty, -1)
VideoPlayerPanel.Children.Add(Player)
VolumeSlider.Value = 50
End Sub
I have tried VerticalAlignment="Center" and VerticalAlignment="Stretch" in XAML on the VideoPlayerPanel, with Center the video disappears entirely, with Stretch it still aligns to the top.
Any thoughts as to what I might do to align this centrally would be much appreciated!
When adding Player dynamiccaly you have different result, because you wrap Play in additional Grid. Try to add Player directly to first row of LayoutParent:
Player.SetValue(Grid.Row, 0)
LayoutParent.Children.Add(Player)
Thanks to all that replied.
I did some more research, I substituted in a Rectangle for the player control and it aligned perfectly. That led me to discover that the third party control was itself at fault. I had to get the source and change the VerticalAlignment directly.
Sorry for the runaround.
Remove Height="*" from first Row . * is used to occupy remaining space, so it is good to use it for the last Row.
Use fixed width and or Auto.

how to get the height of a row in a grid WPF

I have a Grid and into one of its cells I am adding and removing User Controls programmatically.The code to do that looks something like this
this.mainRegion.Children.Add(RibbonRegion);// mainRegion is a Grid and Ribbon Region is a user control
Grid.SetRow(RibbonRegion, RegionIndex);
Here is the thing I want to get the height of the Row that is RegionIndex so that I can get the RibbonRegion control to fill up alL the available space otherwise there is just too much white space the user control is occupying a very small part of the Row.
I basically want to say something like UserControl.Height=RowHeight
Can I do that
Instead of playing with height in procedural code, I would suggest to put the constraint on height in XAML itself at time of RowDefinitions declaration. Set the height to * for your row so that it will take all the available space.
Something like this (assuming you want to place it in second column):
<Grid x:Name="mainRegion">
<Grid.RowDefinitions>
<RowDefinition/>
<RowDefinition Height="*"/>
</Grid.RowDefinitions>
.......
</Grid>

WPF adding stackpanel with border to grid gives error

I'm working on a nested grid/stackpanel/grid window in WPF. Its a Calander, with a maingrid cell being a day. In this day there's a textbox and a stackpanel. The stackpanel contains a grid. EVerything is done in c#, build at run time, because the layout changes with the current month/year. No major problems sofar except when I want to add a border to a stackpanel. It gives the following error:
An unhandled exception of type 'System.Windows.Markup.XamlParseException' occurred in PresentationFramework.dll
Additional information: 'The invocation of the constructor on type 'ADBF.ToezAcad.Admin.OpleidingKalender.MainWindow' that matches the specified binding constraints threw an exception.' Line number '3' and line position '9'.
Nothing special at this position.
Funny thing is it only gives this error, the moment I add the stackpanel ( with border ) to the containing grid.
short version of the code:
Border stackpanelborder = new Border();
this.Content = stackpanelborder;
StackPanel stackpanel = new StackPanel();
stackpanelborder.Child = stackpanel;
Grid.SetColumn(stackpanel, m);
Grid.SetRow(stackpanel, d + 1);
mainGrid.Children.Add(stackpanel); // if I uncomment this line, it throws the error.
Any help would be highly appreciated,
Arnold
#ADBF you are adding the StackPanel to two different child collections. Each UIElement should only have one parent in the visual tree, though a UIElement may have many children, depending on it's type.
I think you wanted to add stackpanelborder to the children of the mainGrid instead.
Edit:
Also you should be referencing stackpanelborder in the SetColumn/SetRow Methods not stackpanel.
The reason being since stackpanel is a child of stackpanelborder it will render inside the that UIElement. However stackpanelborder needs to be told where to insert in the grid, assuming you intend to add additional columns/rows later.
Basically your XAML document if you had one should look like this:
<Grid Name="mainGrid">
<Grid.ColumnDefinitions>
<ColumnDefinition .../>
<ColumnDefinition .../>
</Grid.ColumnDefinitions>
<Grid.RowDefinitions>
<RowDefinition .../>
<RowDefinition .../>
</Grid.RowDefinitions>
<Border Name="stackpanelborder" Grid.Row="0" Grid.Column="0" ...>
<StackPanel Name="stackpanel" .../>
</Border>
</Grid>

DataGrid not shirking to fit into the containing grid

I have the following structure in my WPF application. (Using Prism and Regions)
Window---->
UserControl---->
DockPanel------>
Grid(2X2)------>Row0Col0--
Grid (2X1)------>
ItemsControl------>
UserControl(injected into ItemsControl with Prism)----->
DockPanel----->
DataGrid.(60 rows, 10 columns)
The behavior that I expect is that the DataGrid will size itself to fit the size of the grid cell and display both scrollbars because it is too big to fit. But it doesnt. It remains its maximum size and cuts out of the edges of the grid cell. All cells of both grids have no size specifications (Auto Sized). When I explicitly specify datagrid's height and width, I see the scrollbars, but of course I don't want to do that.
Please help!.
Thanks
I have saved the screenshots at the following link.
http://s1199.photobucket.com/albums/aa467/vikasgoyalgzs/
You say: "All cells of both grids have no size specifications (Auto Sized)" - this is where the problem is. When the grid cell is auto sized the grid gives the content in that cell as much space as it wants (doesn't matter if it fits in the window or not). To fix it you have to put your DataGrid into a star-sized cell.
<Grid>
<Grid.RowDefinitions>
<RowDefinition Height="Auto"/>
<RowDefinition Height="*"/>
</Grid.RowDefinitions>
<Border Grid.Row="0">
<!-- Content that will take as much space as it wants -->
</Border>
<Border Grid.Row="1">
<!-- Content that will take all the remaining space -->
</Border>
</Grid>
UPDATE: Based on the screenshots you provided...
First, get rid of the DockPanel in the top level control. DockPanel gives its child all the space it asks for. If it is not a "fill" child (LastChildFill="True"). Use grid instead of DockPanel (i.e. at the top level a grid with two rows - one auto-sized for the menu and the second star-size for the rest of the stuff, the in that star-size row put another grid for you items controls, etc.).
Remember, whenever you put the content either in an auto-size cell in a grid or in a DockPanel with dock type different than Fill, the content will take as much space as it required without showing a scroll bar (it will go beyond the window).
UPDATE 2: Looking at the new screenshots (see comments to this post)...
OK, I think I see the problem. The thing is that ItemsControl uses StackPanel to display its children, but StackPanel also gives its children all the space they want (your DataGrid thinks that it has enough space to render itself without scroll bars).
To fix that you need to put your items controls inside an ScrollViewer like this:
<ScrollViewer VerticalScrollBarVisibility="Auto"
HorizontalScrollBarVisibility="Auto">
<ItemsControl ... />
</ScrollViewer>

how can i add a row dynamically in WPF?

I need to create a row in XAML which has a label,two radio buttons.. Based on some operation i need these row to be visible..else i need it to hidden.. I do not want the empty space to be displayed.. Is this possible only through code? If so can anyone help me out please?
Place the row in a grid and set it's height set to 'Auto'. Place your controls in a grid (or other container) and set it's Visibility to Collapsed for not visible and Visible for when you need to show it.
<Grid>
<Grid.RowDefinitions>
<RowDefinition />
...
<RowDefinition Height="Auto" /> <!-- Your 'hidden' row -->
...
</Grid.RowDefinitions>
<!-- your collapse content -->
<Grid Grid.Row="2" Visible="Collapsed" x:Name="hiddenRow">
....your controls...
</Grid>
</Grid>
Then to show the controls...
hiddenRow.Visible= Visibility.Visible;
Hope that helps....
What do you mean by "row"? A DataGridRow? An item in a vertical StackPanel?
Is this row part of a DataTemplate for an item?
Without knowing more, it's hard to say.
But basically, you can bind some value trough a ValueConverter to the UIElement.Visibility property if what you want is to hide/show any UiElement.

Resources