Grid SharedSizeGroup - columns are bouncing, resizing in infinite loop - wpf

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?

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.

Recreating WinForms layout in WPF

I've just inherited an old WinForms app with a UI layout like this:
I'm tasked with updating several things about the software one of which is porting it to WPF which I've not previously worked with. I'm also told that the new WPF UI must look identical to the existing UI layout so I'm trying to figure out how to create that layout in WPF. I need a toolbar across the top of the window which stretches the entire width of the fixed-size window. Can I do that in the default grid or do I need a dockpanel to do that? Also, I'm assuming that I would use a grid with 2 columns and 3 rows to layout the six groupboxes?
Anything you can do with a DockPanel can also be done with a Grid -- the DockPanel is just a shortcut. So yes, you can do all this with the default Grid.
As for how to do the layout: it depends on how you want things to resize. Does everything stay proportional when you resize? If so, a single Grid with three columns (and percentage sizes for the ColumnDefinitions) would be fine. You would actually need four rows, though, not three -- the first RowDefinition would be for the ToolBar (using ColumnSpan="3") and would need Height="Auto" so it uses the ToolBar's default size; the remaining rows would be percentage-sized.
Try that, see if it works for you. If the resizing needs to be more complicated than just proportional, then post a second screenshot of the window at a different size, and we could try to help you further.
Personally I would use a DockPanel for the Menu/Content areas, then use a Grid in the Content Area to define the GroupBoxes
<DockPanel>
<Grid x:Name="MenuRegion" DockPanel.Dock="Top" />
<Grid>
<Grid.RowDefinitions>
<RowDefinition Height="*" />
<RowDefinition Height="*" />
<RowDefinition Height="*" />
</Grid.RowDefinitions>
<Grid.ColumnDefinitions>
<ColumnDefinition Width="2*" />
<ColumnDefinition Width="*" />
<ColumnDefinition Width="*" />
</Grid.ColumnDefinitions>
</Grid>
<Grid Grid.Row="0" Grid.Column="0" Grid.ColumnSpan="2" />
<Grid Grid.Row="0" Grid.Column="2" />
<Grid Grid.Row="1" Grid.Column="0" Grid.ColumnSpan="2" />
<Grid Grid.Row="1" Grid.Column="2" />
<Grid Grid.Row="2" Grid.Column="0" />
<Grid Grid.Row="2" Grid.Column="1" Grid.ColumnSpan="2" />
</DockPanel>
Of course, you could also make the Menu area part of the Grid and set it to span all rows, but I personally like keeping them separate.
Grid with 3 row (one for the menu). Since you have uneven spacing in the rows just a single column on the main grid. Then grid in the grid for the two column spacings.

grid splitter with a table

I have a grid splitter that works good. On the left side of the splitter i am trying to have a table with a bunch of images that when the splitter is is moved to the right the images stretch. Which this works fine. However, when the splitter is moved to the left i want the images to move into eachother and when they get there i want the splitter to move over them to make them dissapear. What it does now is the images just squish together until they dissapear. I built a table. I will include some table code and some pics of the behavior i wnat and what its doing. I am trying to replicate the googles kitchen sink example.
I am trying keep this post small
<Grid Background="#FFF8F5F5" ShowGridLines="true" FlowDirection="RightToLeft">
<Grid.ColumnDefinitions>
<ColumnDefinition />
<ColumnDefinition />
<ColumnDefinition />
<ColumnDefinition />
</Grid.ColumnDefinitions>
<Grid.RowDefinitions>
<RowDefinition Height="104*" />
<RowDefinition Height="91*" />
<RowDefinition Height="14*" />
<RowDefinition Height="104*" />
<RowDefinition Height="104*" />
</Grid.RowDefinitions>
<Image Grid.Column="1" Margin="53,3,41,0" Source="google.png" Stretch="Fill" />
<Image Grid.Row="3" Margin="59,4.4,50,0" Source="google.png" Stretch="Fill" />
</Grid>
Here is what i want it to do when move the splitter to the left
and to the right
but this is what it is doing when i move the splitter to the left..
As you can see the images are just scrunching together. Can i do this with tables or do i need a different layout?
Do not set Stretch to Fill but Uniform, also set a fixed size on the Images themselves.

Using SharedSizeGroup with ColumnSpan in a Wpf Grid

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>

Resources