Using SharedSizeGroup with ColumnSpan in a Wpf Grid - wpf

When I create a grid using both a SharedSizeGroup on columns and a column spanning control, the grid goes 'mental' jerking around and maxing out a cpu core.
I'm sure there must be a good reason why this doesn't work but I can't think of it! How else can I achieve this sizing layout?
<Grid IsSharedSizeScope="True">
<Grid.ColumnDefinitions>
<ColumnDefinition Width="Auto" SharedSizeGroup="Columns"/>
<ColumnDefinition Width="Auto" SharedSizeGroup="Columns"/>
</Grid.ColumnDefinitions>
<Grid.RowDefinitions>
<RowDefinition Height="Auto"/>
<RowDefinition Height="Auto"/>
</Grid.RowDefinitions>
<Label Grid.Column="0">Blah</Label>
<Label Grid.Column="1">Blah Blah Blah Blah</Label>
<Label Grid.Row="1" Grid.ColumnSpan="2">ajsgdeererajgsfdg dfg df gdfg djgsad</Label>
</Grid>

What you've done is essentially set up infinite recursion in your layout.
To share sizing the Columns first need to calculate their own size.
They can then sync up based on the
larger one (probably Column 1 here).
After Column 0 expands to match
Column 1's size, the third label can
now use more of the space in Column
As it shifts columns, the space it
needs in Column 1 becomes smaller,
allowing Column 1 to scale down to
match the new space required by its
contents.
Column 1 now recalculates its size (start over at the first step)
SharedSizeGroup is intended to be used across different Grids to maintain alignment of elements that are somehow separated into different containers, like different templated list items or a header row. If you need an equally split row that isn't stretched you could use something else like * sized columns or a UniformGrid instead.
<Grid>
<Grid.RowDefinitions>
<RowDefinition Height="Auto"/>
<RowDefinition Height="Auto"/>
</Grid.RowDefinitions>
<UniformGrid Rows="1" HorizontalAlignment="Left">
<Label >Blah</Label>
<Label >Blah Blah Blah Blah</Label>
</UniformGrid>
<Label Grid.Row="1">ajsgdeererajgsfdg dfg df gdfg djgsad</Label>
</Grid>

Related

Grid width "*" not behaving as expected when parent size is not defined

I have a set of controls in a dialog box that I want to auto-size. Everything worked fine until I tried to re-arange things using an evenly spaced Grid width.
Here's the XAML:
<Grid Margin="20" >
<Grid.RowDefinitions>
<RowDefinition Height="AUTO" />
<RowDefinition Height="AUTO" />
</Grid.RowDefinitions>
<Grid.ColumnDefinitions>
<ColumnDefinition Width="2*"/>
<ColumnDefinition Width="*"/>
</Grid.ColumnDefinitions>
<Grid>
...left controls
</Grid>
<Border BorderThickness="1" BorderBrush="Gray" Grid.Column="1" Margin="0,10,0,5">
...right controls
</Border>
<Grid Grid.Row="2" Grid.ColumnSpan="2>
...okay and cancel
</Grid>
</Grid>
Here's the result:
Not what I'm expecting. The right column has a tiny width, for some reason it's not listening to the "*" and making it equal to the half the other column.
If I put a Width="450" on the highest Grid, or UserControl (or during runtime, resize the window it sits in!) Everything "jumps" and I get what I'm expecting, both columns evenly spaced:
But now it doesn't respond to re-sizing, or auto-size for larger content (except that wouldn't stretch when the parent container stretched) If I were after equal spacing I could use a shared size group. Is there anything I'm doing wrong or is this expected behavior for Width="*"?
When your outer Grid is hosted in a container where the width is not defined, the actual width will be the result of the descendant. That is, the (outer) Grid measure pass will "ask" to the right column (the Border): "I'm giving you whatever space you want: how much do you need?". As long the Border fragment won't require any specific size, the result is the default (zero, in most cases). Hence the collapsed behavior.
Basically, you should either define the outer Grid width, or the 2nd column width (by mean anything within the column should tell how much space it needs).
You are right * means to take size proportional to grid. It happens cause your the highest Grid does not enough space to be wider( when you set Width="450", then the Grid becomes wider).
If you have just one grid inside your Window, then the theSecondColumn will take all place at the right side(it will be wider as you want):
<Window x:Class="DataGridAddedColumns.MainWindow"
<!-- The code is omitted for the brevity -->
Title="MainWindow" Height="550" Width="525"
WindowStartupLocation="CenterScreen">
<Grid Name="grid">
<Grid.RowDefinitions>
<RowDefinition />
<RowDefinition/>
</Grid.RowDefinitions>
<Grid.ColumnDefinitions>
<ColumnDefinition Width="2*"/>
<ColumnDefinition Name="theSecondColumn" Width="*"/>
</Grid.ColumnDefinitions>
<Grid>
</Window>

How to: datagrid cell size changed when windows size changed

Firstly, my window is set to 900px height and 600px width. It contains a datagrid with 4 columns. I've created a template for cells, the widths are, say, 100px. Now when I change the window sizes, I want cells' width to grow proportionally to size of windows. I tried to add datagrid sizes change event but it didn't work.
How can I do this? Thanks!
Update: one more question: Have any way to make the sizes of a cell is the same whether they're empty or not.
In grid definition
<Grid HorizontalAlignment="Stretch" VerticalAlignment="Stretch">
<Grid.RowDefinitions>
<RowDefinition Height="5*"/>
<RowDefinition Height="Auto"/>
</Grid.RowDefinitions>
<Grid.ColumnDefinitions>
<ColumnDefinition Width="5*" MinWidth="70" />
<ColumnDefinition Width="Auto" />
...
MinWidth : Gets or sets the minimum width constraint of the element.

MulitGrid with Child Grids Contents being sized accordingly

I dont know if this has been answered but what i am trying to to do is i have a parentGrid with 3 rows, the first two are a menu strip and a toolbar, the third row is a child grid that is populated with the choices that are selected from the tool bar. the problem is that i want the forms that load in the child grid to not have their height surpass what i have set that row equal to in the parentGrid.
is there an effective way to do this?
here is basically what i have for code
<Grid x:Name="ParentGrid" Margin="0" >
<Grid.RowDefinitions>
<RowDefinition Height="22"></RowDefinition>
<RowDefinition Height="90"></RowDefinition>
<RowDefinition Height="544*"></RowDefinition>
<!--516<RowDefinition Height="80*"></RowDefinition>
<RowDefinition Height="10*"></RowDefinition>-->
</Grid.RowDefinitions>
<DockPanel></DockPanel><!--Dock Panel Menu Strip-->
<DockPanel></DockPanel><!-- Dock Panel ToolBar-->
<Grid x:Name="ChildGrid" Grid.Row="2" Height="544">
</Grid>
</Grid>
Set the Height in your RowDefinition to whatever you want your Grid's height to be, then create an extra RowDefinition with a Height="*" to take up the remaining space
<Grid x:Name="ParentGrid" Margin="0" >
<Grid.RowDefinitions>
<RowDefinition Height="22"></RowDefinition>
<RowDefinition Height="90"></RowDefinition>
<RowDefinition Height="544"></RowDefinition>
<RowDefinition Height="*"></RowDefinition>
</Grid.RowDefinitions>
<DockPanel></DockPanel><!--Dock Panel Menu Strip-->
<DockPanel></DockPanel><!-- Dock Panel ToolBar-->
<Grid x:Name="ChildGrid" Grid.Row="2">
</Grid>
</Grid>
The * in your RowDefinitions mean "all remaining space". Adding a number to it defines the ratio of remaining space that column will get. For example, if you say one column is going to be 1* and another is going to be 2*, it means the 2nd column is going to take up twice the space as the first one. If you have one column taking up 544* and another taking up 10*, it means the available space will get split into 554 parts, and 544 parts will get given to the first column and 10 parts will be given to 2nd column.
The solution that worked for me was that instead of using a Grid as the inner child i used a ScrollViewer as the container

Grid SharedSizeGroup - columns are bouncing, resizing in infinite loop

I need table with both horizontal and vertical header (simple PivotGrid). I have found some similar (or almost same) problems here, but no one give the solution. In XAML I have defined this structure:
<Grid x:Name="grdMain" Background="White" Grid.IsSharedSizeScope="True">
<Grid.ColumnDefinitions>
<ColumnDefinition Width="Auto"/>
<ColumnDefinition Width="Auto"/>
<ColumnDefinition Width="Auto"/>
</Grid.ColumnDefinitions>
<Grid.RowDefinitions>
<RowDefinition Height="Auto"/>
<RowDefinition Height="Auto"/>
<RowDefinition Height="Auto"/>
</Grid.RowDefinitions>
<Grid Grid.Row="0" Grid.Column="1" x:Name="grdHorizontalHeader">
<!-- place for column definitions and header labels defined in code -->
</Grid>
<Grid Grid.Row="1" Grid.Column="0" x:Name="grdVerticalHeader">
<!-- place for column definitions and header labels defined in code -->
</Grid>
<Grid Grid.Row="1" Grid.Column="1" x:Name="grdContent">
<!-- place for column definitions and header labels defined in code -->
</Grid>
</Grid>
So both header consist of grid with some ColumnDefinitions (resp. RowDefinitions) and I need to size Header-ColumnDefinitions according to Content-ColumnDefinitions. I do it in code:
foreach (var row in myColumnSource)
{
// Content columns definitions
var cD = new ColumnDefinition();
cD.Width = GridLength.Auto;
cD.SharedSizeGroup = "ColumnSharedSizeGroup" + row.Value;
this.grdContent.ColumnDefinitions.Add(cD);
// Header columns definitions
var cD2 = new ColumnDefinition();
cD2.Width = GridLength.Auto;
cD2.SharedSizeGroup = "ColumnSharedSizeGroup" + row.Value;
this.grdHorizontalHeader.ColumnDefinitions.Add(cD2);
...
So Header-Column should share it's Width with Content-Column. But when I run the program, the columns are bouncing and resizing in infinite loop. Row's height sharing work fine. Where could be the problem?
EDIT only columns in header (grdHorizontalHeader) are resizing. Columns in grdContent have correct and stable width.
The Grid control's algorithm for auto-sizing can be finicky sometimes.
Have you tried setting a MinWidth on each of your columns/rows?
<Grid.ColumnDefinitions>
<ColumnDefinition Width="Auto" MinWidth="30" />
<ColumnDefinition Width="Auto" MinWidth="30" />
<ColumnDefinition Width="Auto" MinWidth="30" />
</Grid.ColumnDefinitions>
<Grid.RowDefinitions>
<RowDefinition Height="Auto" MinHeight="15" />
<RowDefinition Height="Auto" MinHeight="15" />
<RowDefinition Height="Auto" MinHeight="15" />
</Grid.RowDefinitions>
Not super elegant, but fixed this same problem for us.
If one grid has many SharedSizeGroup columns, the resulting layout performs an exponentially increasing number of passes to try and sort them out. Someone somewhere said Microsoft acknowledged the bug, but I couldn't find details of it.
To solve the issue, I broke my grid up into smaller grids inside a StackPanel. This made the layout fast again and retained the shared sizing.
As your grid is two dimensional, this would be harder. As you are adding controls dynamically, perhaps you could have one vertical StackPanel holding horizontal StackPanels holding smaller Grids?

How to access actual Height of Elements with Height=Auto

I have a situation like this:
<Grid>
<Grid.ColumnDefinitions>
<ColumnDefinition Width="560"/>
<ColumnDefinition Width="250"/>
</Grid.ColumnDefinitions>
<Grid.RowDefinitions>
<RowDefinition Height="Auto" /> <!-- status infos & content start -->
<RowDefinition Height="Auto" /> <!-- status infos -->
<RowDefinition Height="Auto" /> <!-- status infos -->
<RowDefinition Height="Auto" /> <!-- status infos -->
<RowDefinition Height="*"/> <!-- content ends -->
</Grid.RowDefinitions>
<!-- image a list of custom controls directed to the first or second column on all rows here -->
<SomeCustomControl Grid.Row="0" Grid.Column="0" Grid.ColumnSpan="2" Grid.RowSpan="2" />
</Grid>
As you can see I have 2 Columns, the right one is more or less reserved for status information, the left for content. "SomeCustomControl" contains a control so wide it needs to be set to ColumnSpan="2". Notice there are still the status control in the right column. In SomeCustomControl I have something like this:
<Grid x:Name="LayoutRoot">
<Grid.ColumnDefinitions>
<ColumnDefinition Width="*"/>
<ColumnDefinition Width="250"/>
</Grid.ColumnDefinitions>
<Grid.RowDefinitions>
<RowDefinition Height="Auto" />
[...]
<RowDefinition Height="Auto" />
<RowDefinition Height="*" /> <!-- problem control here -->
<RowDefinition Height="Auto" />
</Grid.RowDefinitions>
<!-- a list of Controls limited to the first column -->
<ProblemControl Grid.Column="0" Grid.ColumnSpan="2" />
</Grid>
Now, the first Rows of SomeCustomControl contain controls limited to the first column, then there is a row that contains my ProblemControl. The Height of the status controls is not predetermined and depends on the shown status information. The controls in SomeCustomControl that are limited to the first column also have different heights, that are currently determined automatically through the content.
I now have the problem that ProblemControl overlaps with some of my status controls. I tried to calculate the height of my status controls and the limited controls in SomeCustomControl, but as all controls are sized dynamically I can't seem to get correct Heights. The Height of the RowDefinitions all contains Heights of type Auto and value 1, the Heights of the concrete Controls seems to be NaN.
Any ideas as to how I can calc the heights or prevent the overlapings in other ways.
I've encountered somewhat of the same problem, but came across the solution recently. The reason why you can't access the width and height properties of a control with width or height set to Auto is that the run time system is querying for the property values before they've been set. The properties ActualWidth and ActualHeight claim to get the rendered height of controls so in theory, you'd think you could simply wait until the SL application had finished loading and then perform your query, since the controls would be rendered by then and therefore, the ActualHeight/ActualWidth values should be set.
Sadly, this isn't the case either. There doesn't seem to be any guarantee when those values are set, so the workaround I used is to hook into the SizeChanged-event of the control whose values I want. SizeChanged is triggered whenever the width and height properties of a control are changed, so if I handle that event, I am guaranteed that the values are set to something other than NaN.
Do whatever logic you need to perform in a handler for that event, and you'll find the values are set.
Have you tried with ActualHeight property on control ?
You ought to be able to solve this with proper use of the Grid and some panels (DockPanel and StackPanel can be quite useful). You may also need the HorizontalAlignment or VerticalAlignment properties set to Stretch on some controls.
Your example doesn't have enough in it for us to duplicate your problem or to know that we've addressed it correctly. If you'd like more specific help, please expand the example so we can run it and see your issue.

Resources