使用SharedSizeGroup列的网格表现得非常奇怪(* NOT *无限循环)

时间:2012-01-14 01:07:50

标签: c# wpf performance xaml .net-4.0

如果您运行下面的示例窗口,则上面的ItemsControl将更新布局几秒钟,直到最后所有列都具有正确的宽度(正确=与较低ItemsControl中的列相同)。

您可以更改窗口的宽度并水平和垂直滚动ScrollViewer周围的较低ItemsControls - 但只要更改窗口的高度,布局就会翻转几秒钟。

注意:没有尺寸模糊,就像网格无限更新尺寸的其他问题一样。

我做错了什么 - 如果是的话,我怎么能解决这个问题? - 或者我应该将此问题发布到Microsoft-Connect?

代码背后:

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>

顺便说一句:如果强制上部ItemsControl的项目是大小给定(通过向GroupBox添加MinWidth="200"),那么较低的ItemsControl将会变得愚蠢。

BTW2:从大约开始8个共享大小的列(在示例中有15个,由.Take(15)控制),您会看到重新排列显示,并且它会在您添加的每个列的时间内翻倍 - 因此20列几乎不会结束几分钟。

BTW3:3个月内没有收到任何评论非常令人沮丧。

2 个答案:

答案 0 :(得分:2)

好有趣的是,我在三个月前给这个问题+1了但是没有回答。可能你没有得到回应的原因是因为它很难!

我现在还没有太多话要说,除了WPF布局是在两遍中执行 - 测量和排列 - 随后的元素大小调整可能会触发其他元素的布局......

为了正确调整列的大小,WPF正在执行以下操作:

  • 测量第1列内容
  • 安排第1栏内容
  • 测量第2列内容
    • 等一下,第2列比预期的要大
    • 触发所有第1列内容的度量
      • 安排第1栏内容
      • 测量第2列内容

...等

为我简单化的观点道歉。您有多少列(因此共享大小组的数量)?另一个问题。您运行的操作系统和.NET Framework是什么?我听说在WindowsXP上的WPF中可能存在的SharedSizeGroup数量有限制。不确定它是否在以后的操作系统中修复。

作为一种解决方法,您可以自己实施此行为吗?意思是你可以创建自己的附加属性来测量网格中的每个元素(所有列,所有行)然后设置每列的大小一次吗?而不是逐列的基础。

问候,

答案 1 :(得分:1)

我有类似的问题。我的确切情况后面是我如何解决它。

我有一个“网格”,其中顶行和左列保持原位,其余内容滚动(如冻结的Excel单元格)。内容的大小是变化的并且在运行时确定。也很难预测它的大小。

为了构建这个,我总共有4个网格 - 1个外部网格用于布局,3个网格在其中 - 1个用于顶行元素,1个用于左列元素,1个用于实际内容。内容网格的行通过共享大小组同步到左列的行,同样与内容列和顶行列同步。

为了解决这个问题,我首先在后面的代码中填充了实际网格的数据。然后我在外部网格对象上调用了Measure and Arrange来强制渲染它。请参阅此处了解如何执行此操作。 https://stackoverflow.com/a/4890217/2352625

通过强制渲染,我有每个单元格的实际大小,然后我用它来创建标题的行和列定义(而不是将它们设置为自动大小)。它仍然不完美 - 当我显示一个大网格时 - 但是移动很小(几个像素),而不是像现在一样跳过。