how to get the height of a row in a grid WPF - 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>

Related

wpf grid with automatic number of rows

I am aware that I can use Grid.Rowdefinitions to define the number of rows and their properties on a WPF Grid control.
However is there a way to set the grid to automatically grow/add rows as controls are added, without having to explicitly state it?
However is there a way to set the grid to automatically grow/add rows as controls are added, without having to explicitly state it?
No, there isn't. Depending on your requirements, you probably want to replace the Grid with another Panel like for example a StackPanel or a UniformGrid with a single column:
<UniformGrid x:Name="grid" Columns="1" />
Then you don't need to care about setting any Grid.Row property.
You can do that in your code behind.
Define following in the .xaml of your window:
<Grid x:Name="YourGrid">
<Grid.RowDefinitions>
<RowDefinition Height="auto"/>
</Grid.RowDefinitions>
</Grid>
Now use a loop to create as many rows as you need:
foreach(Control control in controlls)
{
YourGrid.RowDefinitions.Add(new RowDefinition());
YourGrid.Children.Add(control);
Grid.SetRow(control , YourGrid.RowDefinitions.Count - 1);
}
If you have a lot of controls this could help you. It will add the control automatically into the created row.
If you don't want to add the controls and rows in the code behind, you will have to add the rows manually. As far as I know there is no way to automate it.

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

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.

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>

resolution issue in silverlight

HI, i need to have a resolution independant UI in silverlight application. Will it support implicitly or should it be taken care in code behind doing ScaleTransform ?
will it support multiple browsers as well ?
Thanks in advance.
You can use The ViewBox control in the Silverlight Toolkit to do the scale transforming. It will work on all supported browsers.
You can also set the UserControl width and height to Auto (or remove them) and then have your UI stretch (but not resize) to rules that you set up (typically with a Grid control).
Okay, I figured I will outline all the methods that you can make use of the implicit methods that Silverlight allow for specifying sizing.
If you define anything using the Stretch setting for VerticalAlignment option in a control:
<TextBox Grid.Column="0" Grid.Row="0" VerticalAlignment="Stretch" HorizontalAlignment="Stretch"/>
The UIElement will stretch to take up all the space available to it in its parent control. Another setting such as this is to do something like defining a grid column width or row height like this:
<ColumnDefinition Width="*"/>
This will take up all the space available on the screen.
You can grow columns and rows of the grid in a ratio form:
<RowDefinition Height="3*"/>
<RowDefinition Height="2*"/>
This will grow the height of the first row by 3px for each 2px that the second one grows.
Then you can have options such as Auto
<ColumnDefinition Width="Auto"/>
This will grow the UIElement according to size requirements. If a child of the element requires more size, the element will take up more screen space.
And finally:
<TextBox Grid.Column="1" Grid.Row="0" Height="100" MinWidth="200" MaxWidth="400" x:Name="text"/>
These are fixed values and ensures that given any resolution that the element will not take up more than 400px in width but no less than 200px. It also indicates that the height of the element should always be 100px. This is useful for elements such as buttons etc. which you do not want to grow or shrink as the resolution changes.
Finally, you will probably want to wrap a ScrollViewer around the whole thing, just to ensure that elements off the screen can be scrolled to. This can happen when your view requires more space than available on the screen or have elements set to Auto.

WPF Grid and DataGrid sizing

The UserControl I'm trying to work with is essentially laid out like so:
<Grid>
<Grid.RowDefinitions>
<Row Height="*"/>
<Row Height="*"/>
</Grid.RowDefinitions>
<wpftoolkit:DataGrid x:Name="PrimaryGrid"/> <!-- ~10 rows -->
<Border>
<Grid>
<Grid.RowDefinitions>
<Row Height="*"/>
<Row Height="*"/>
</Grid.RowDefinitions>
<wpftoolkit:DataGrid x:Name="SecondaryGrid"/> <!-- ~2 rows -->
<wpftoolkit:DataGrid x:Name="OtherGrid"/> <!-- ~50 rows -->
</Grid>
</Border>
</Grid>
This UserControl is then placed in my Window as the last member of a Grid, the only one with Height="*". I'm having problems with the way the DataGrids are sized.
If I set VerticalAlignment of the UserControl to Stretch in the Window, then PrimaryGrid gets 1/2 height of the UserControl, and each of the two inside the Border get 1/4. They are sized like this regardless of the number of rows each have, leaving OtherGrid with too little vertical space and the others with non-row whitespace inside the scrollview.
If I set VerticalAlignment to Top, the grids seem to size pretty well to their contents, except there is an inexplicable whitespace being left at the bottom of the UserControl. I used Snoop and the RowDefinition for the UserControl has the proper ActualHeight, but the UserControl only uses a portion of it - 80% or so.
I don't really mind whether I fix the Stretch case (How do I make the DataGrid not stretch larger than its number of rows?) or the Top case (How do I make the UserControl use all the space it has available to it?)
Summary: Use Stretch for the UserControl, but Auto (instead of *) for the row heights inside your UserControl.
Explanation: "Auto" means: as much space as needed (which is what you want), whereas "*" means: a proportional share of all available space (resulting in the 1/2, 1/4, 1/4-distribution).
Since you want the UserControl to use all available space, Stretch is the correct option (it means exactly that). Set one of the row heights inside the UserControl back to "*", if you want this row to take up the remaining available space.
This is a common problem where what you really want is 2 completely different layout behaviors: Auto sizing when there's room for all three, * sizing when there isn't. Some quick fixes you can try out with limitations:
Auto sizing (as already mentioned)
DockPanel with each set to Dock=Top - this will have a similar effect to VerticalAlignment=Top but the last DataGrid (only 1) will stretch out to fill the remaining space. Also bad if the first or second take up more space than exists because they'll push the others out.
Set MinHeight/MaxHeight in combination with one of the other 2 changes on your DataGrids to keep them from getting out of control. This gives up some of the auto-layout flexibility in exchange for making sure everything shows up.
Beyond those you can try something more complex like creating a custom Panel (or find one that someone else made already), or creating a MultiValueConverter that can calculate appropriate Height (or MinHeight, MaxHeight) settings for each DG or Row based on the height of the UC and each of the DGs.
Well, here's what I ended up with. It does what I want from a layout point of view, mostly. A bit more code behind than I'd like, but oh well.
In my DataContextChanged event handler:
//for each grid
_reportObserver = new PropertyObserver<ItemCollection>(PrimaryGrid.Items)
.RegisterHandler(c => c.Count, c => UpdateMaxHeight(PrimaryGrid));
UpdateMaxHeight(PrimaryGrid);
PropertyObserver is from http://joshsmithonwpf.wordpress.com/2009/07/11/one-way-to-avoid-messy-propertychanged-event-handling/
//Lots of ugly hard-coding
private void UpdateMaxHeight(DataGrid grid)
{
double header_height = grid.ColumnHeaderHeight;
if (double.IsNaN(header_height))
header_height = 22;
double margin_height = grid.Margin.Bottom + grid.Margin.Top;
grid.MaxHeight = header_height + margin_height + grid.Items.Count * (grid.RowHeight+2);
UpdateLayout(); //this is key for changes to number of items at runtime
}
Even after setting the DataGrid's MaxHeight, things were still ugly, so I had to set the max height on the RowDefinition's too. But that still wasn't right, causing the margin_height addition above.
<RowDefinition Height="*" MaxHeight="{Binding ElementName=PrimaryGrid, Path=MaxHeight}"/>
At some point, I'll take into account my optionally visible row details in my ugly max height code.
As far as Top vs Stretch, I ended up for other reasons having the usercontrol in a ListView. Everything sizes nicely now.
Thanks again for looking at my problem.
Just wanted to follow up on this problem. Over time, the solution I provided above just did not meet users expectations. I've now changed to a scheme like this:
<ScrollViewer VerticalScrollBarVisibility="Auto">
<Grid>
<!-- row definitions -->
<KentBoogart's Resizer ResizeDirection="South">
<DataGrid/>
</kb:Resizer>
<kb:Resizer ResizeDirection="South">
<DataGrid/>
</kb:Resizer>
</Grid>
</ScrollViewer>
In another place where I've used this idiom, I've set the Resizer to have a MaxHeight bound to the ScrollViewer's ActualHeight to keep it from going out of control. This design can be a little confusing with the overall scrollbar, plus scrollbars in the DataGrid, but with good borders and margins, it's not too bad.

Resources