A grid with SharedSizeGroup columns acts very weird (* NOT * an infinite loop)

If you run the sample window below the top ItemsControl, it will update the layout in a few seconds, until finally all the columns have the correct width (correctly = identical to the columns inside the bottom ItemsControl).

You can change the width of the window and scroll the bottom ItemsControls around the ScrollViewer both horizontally and vertically - but as soon as you change the height of the window, the layout will flip for a few seconds.

Note. There is no dimensional uncertainty, as in other matters where the grid infinitely updates the dimensions.

I'm doing something wrong - and if so, how can I fix it? - or should I send this problem to Microsoft-Connect?

Code behind:

namespace DynamicGridColumnBinding { using System; using System.Collections.Generic; using System.Globalization; using System.Linq; using System.Windows; using System.Windows.Controls; public partial class MainWindow { private static readonly CultureInfo[] cultureInfos = CultureInfo.GetCultures(CultureTypes.NeutralCultures).Take(15).ToArray(); public MainWindow() { this.InitializeComponent(); } public static IEnumerable<CultureInfo> AllCultures { get { return cultureInfos; } } private void GridInitialized(object sender, EventArgs e) { var grid = (Grid)sender; for ( int i = 0; i < cultureInfos.Length; i++ ) grid.ColumnDefinitions.Add(new ColumnDefinition { Width = GridLength.Auto, SharedSizeGroup = "g" + i, }); } private void ScrollViewerScrollChanged(object sender, ScrollChangedEventArgs e) { if ( e.HorizontalChange != 0 ) this.legendScroller.ScrollToHorizontalOffset(e.HorizontalOffset); } } } 

Xaml:

 <FrameworkElement.Resources> <ItemsPanelTemplate x:Key="panelTemplate"> <Grid Initialized="GridInitialized" /> </ItemsPanelTemplate> <Style TargetType="ContentPresenter" x:Key="containerStyle"> <Setter Property="Tag" Value="{Binding RelativeSource={RelativeSource Self}, Path=(ItemsControl.AlternationIndex)}" /> <Setter Property="Grid.Column" Value="{Binding RelativeSource={RelativeSource Self}, Path=(ItemsControl.AlternationIndex)}" /> </Style> <Style TargetType="TextBlock" x:Key="textStyle"> <Setter Property="Padding" Value="5" /> <Setter Property="Background" Value="Lime" /> <Setter Property="HorizontalAlignment" Value="Center" /> <Setter Property="VerticalAlignment" Value="Center" /> </Style> </FrameworkElement.Resources> <DockPanel Grid.IsSharedSizeScope="True" DataContext="{Binding Source={x:Static local:MainWindow.AllCultures}}"> <ScrollViewer DockPanel.Dock="Top" HorizontalScrollBarVisibility="Hidden" VerticalScrollBarVisibility="Disabled" x:Name="legendScroller"> <ItemsControl ItemsSource="{Binding}" AlternationCount="{x:Static System:Int32.MaxValue}" Margin="0 0 500 0" ItemsPanel="{StaticResource panelTemplate}" ItemContainerStyle="{StaticResource containerStyle}"> <ItemsControl.ItemTemplate> <DataTemplate DataType="{x:Type glob:CultureInfo}"> <GroupBox Header="{Binding Name}" HeaderStringFormat="[ {0} ]"> <TextBlock Style="{StaticResource textStyle}" Text="{Binding Tag, RelativeSource={RelativeSource AncestorType=ContentPresenter, AncestorLevel=2}}" /> </GroupBox> </DataTemplate> </ItemsControl.ItemTemplate> </ItemsControl> </ScrollViewer> <TextBlock Foreground="Red" DockPanel.Dock="Top" Margin="0 10" FontSize="20" Text="some random arbitrary content in between" /> <ScrollViewer HorizontalScrollBarVisibility="Visible" VerticalScrollBarVisibility="Auto" ScrollChanged="ScrollViewerScrollChanged"> <ItemsControl ItemsSource="{Binding}" AlternationCount="{x:Static System:Int32.MaxValue}" ItemsPanel="{StaticResource panelTemplate}" ItemContainerStyle="{StaticResource containerStyle}"> <ItemsControl.ItemTemplate> <DataTemplate DataType="{x:Type glob:CultureInfo}"> <Border Background="DodgerBlue" Padding="5" Margin="1"> <GroupBox Header="{Binding DisplayName}"> <TextBlock Style="{StaticResource textStyle}" Padding="5 100" Text="{Binding Tag, RelativeSource={RelativeSource AncestorType=ContentPresenter, AncestorLevel=2}}" /> </GroupBox> </Border> </DataTemplate> </ItemsControl.ItemTemplate> </ItemsControl> </ScrollViewer> </DockPanel> 

BTW: If you force the elements of the upper ItemsControl to set size (by adding MinWidth="200" to the GroupBox), then the lower ElementsControl will act stupidly.

BTW2: Starting from approx. 8 columns of total size (in sample 15 controlled by .Take(15) ), you see that the rearrangement appears and it doubles in time with each added column, so 20 columns almost do not end for minutes.

BTW3: Getting more than one comment for 3 months is very frustrating.

+6
source share
2 answers

Ok, pretty funny, I asked this question three months ago, but did not answer. Probably the reason you didnโ€™t get the answer is because it is difficult!

I still have nothing to say now, except that the WPF layout is done in two passes - measuring and ordering - and subsequent calibration of the elements can trigger the layout for other elements, etc.

For the correct column size, WPF does something like this:

  • Dimension Column Content
  • Sort column 1 content
  • Measure the contents of column 2
    • Wait a second, column 2 is more than expected
    • Run measure for all contents of column 1
      • Sort column 1 content
      • Measure the contents of column 2

... etc.

Apologies for my simplistic view. How many columns do you have (hence the number of groups in total size)? Another question. What OS and .NET Framework are you using? I heard that there is a limit to the number of SharedSizeGroups you could have in WPF on WindowsXP, for example. Not sure if it is fixed in later OS versions.

How could you implement this behavior yourself in a workaround? Sense, you can create your own property that measures each element in the grid (all columns, all rows), and then sets the dimensions of each column once? Unlike column by column.

Respectfully,

+2
source

I had a similar problem. My exact situation followed the way I solved it.

I have a โ€œgridโ€ in which the top row and left column remain in place, like the rest of the content scroll (for example, frozen Excel cells). The size of the content varied and was determined at runtime. It was also difficult to predict what size would be.

To build this, I have a total of 4 grids - 1 external grid for the layout and 3 grids inside it - 1 for the elements of the top row, 1 for the elements of the left column and 1 for the actual content. The content grid rows are synchronized with the left column rows using the common size group, as well as the content columns and the top row columns.

To solve this problem, I filled in the data for the actual grid first in the code behind. Then I called Measure and Arrange on the external mesh object to force the visualization on it. See here how to do it. fooobar.com/questions/231326 / ...

By using the render, I have the actual size of each cell, which I then use to create row and column definitions for my headers (instead of setting them to Auto size). This is still not perfect - when I show a large grid, but the offset is slight (a few pixels) instead of jumping all the way, as it were.

+1
source

Source: https://habr.com/ru/post/905956/


All Articles