2012-01-14 11 views
6

Si ejecuta la ventana de muestra a continuación, ItemsControl actualizará el diseño durante varios segundos hasta que finalmente todas las columnas tengan el ancho correcto (correcto = idéntico a las columnas dentro de ItemsControl inferior).Cuadrícula con columnas SharedSizeGroup está actuando muy raro (* NO * bucle infinito)

Puede cambiar el ancho de la ventana y desplazarse por los controles de elementos inferiores que rodean ScrollViewer, tanto horizontal como verticalmente, pero tan pronto como cambie la altura de la ventana, el diseño se invertirá durante varios segundos.

Nota: No existe una ambigüedad de tamaño como en otras preguntas donde la cuadrícula actualiza infinitamente los tamaños.

¿Debo hacer algo mal? Si es así, ¿cómo podría solucionarlo? ¿O debería publicar este problema en Microsoft-Connect?

Código atrás:

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> 

Por cierto: Si se obliga a los elementos de ItemsControl superior a estar dando tamaño (mediante la adición de MinWidth="200" a GroupBox) entonces el ItemsControl inferior en cambio actuará tontamente.

BTW2: Comenzando con aprox. 8 columnas de tamaño compartido (en el ejemplo hay 15, controladas por .Take(15)) se ve la reordenación para aparecer, y se duplica en el tiempo por cada columna que se agrega, por lo que 20 columnas casi no terminan durante unos minutos.

BTW3: No recibir un solo comentario durante 3 meses es muy frustrante.

Respuesta

2

Curiosamente, hice esta pregunta hace tres meses pero no respondí. ¡Probablemente la razón por la que no has recibido respuesta es porque es difícil!

Todavía no tengo mucho que decir ahora, excepto que el diseño de WPF se realiza en dos pasos - medida y organizar - y posterior dimensionamiento de elementos podrían dar lugar a un diseño en otros elementos, etc ...

En para el tamaño de las columnas correctamente WPF está haciendo algo como esto: la columna Medida

  • 1 contenidos
  • Organizar la columna 1 contenidos
  • columna Medida 2 contenidos
    • Espera un segundo, columna 2 es mayor de lo esperado
    • disparador una medida sobre todo la columna 1 contenidos
      • Organizar columna 1 contenidos
      • columna Medida 2 contenidos

...etc.

Disculpas por mi vista simplista. ¿Cuántas columnas tiene (por lo tanto, el número de grupos de tamaño compartido)? Otra pregunta. ¿Qué sistema operativo y .NET Framework está ejecutando? Escuché que había una limitación en el número de SharedSizeGroups que podría tener en WPF en Windows XP, por ejemplo. No estoy seguro de si está arreglado en sistemas operativos posteriores.

Como solución, ¿podría implementar este comportamiento usted mismo? ¿Quiere decir que puede hacer su propia propiedad adjunta que mide cada elemento de la grilla (todas las columnas, todas las filas) y luego establece los tamaños de cada columna una vez? A diferencia de una columna por columna.

Saludos,

+0

La cantidad de columnas varía en el tiempo de ejecución. Estoy usando .NET en W7. No puedo medir todas las columnas y todas las filas porque uno de los 2 ejes tiene que usar un panel de paneles virtualizado. Tal vez debería escribir mi propio Panel usando su propia semántica SharedSize. Actualmente estoy desactivando la asignación de SharedSizeGroup-names si hay más de 7 columnas. – springy76

+0

Sí, acabamos de encontrarnos con esto. Teníamos 10 filas de grupos compartidas y el proceso tardaba unos segundos en estabilizarse después de agregar un nuevo conjunto de filas. En nuestro caso, parecía que la mayoría de las filas eran en realidad de un tamaño fijo que podía codificarse en el XAML. Una vez que la cantidad de grupos compartidos se redujo a 2 (este era el número que realmente se necesitaba para tener un tamaño dinámico), el problema desapareció. Entonces parece que necesita usar esta propiedad con moderación. – briantyler

+0

Lo que no entiendo es: El proceso de medición y organización de 2 pasos normalmente ocurre sin ningún ciclo de pintura entre ellos. Si su ventana contiene demasiados controles, la actualización de la interfaz de usuario se puede retrasar durante varios segundos y toda la aplicación "parece" estar congelada mientras tanto (el hilo principal realmente lo es). – springy76

1

Tuve un problema similar. Mi situación exacta siguió por cómo la resolví.

Tengo una "cuadrícula" construida donde la fila superior y la columna izquierda permanecen en su lugar mientras el resto del contenido se desplaza (como las celdas congeladas de Excel). El tamaño del contenido varió y se determina en tiempo de ejecución. También era difícil predecir cuál sería el tamaño.

Para construir esto, tengo un total de 4 cuadrículas: 1 cuadrícula externa para el diseño y 3 cuadrículas dentro de ella, 1 para los elementos de la fila superior, 1 para los elementos de la columna izquierda y 1 para el contenido real. Las filas de la cuadrícula de contenido se sincronizan con las filas de la columna izquierda a través de un grupo de tamaño compartido y de la misma manera con las columnas del contenido y las columnas de la fila superior.

Para resolverlo, llené los datos de la cuadrícula real primero en el código de detrás. Luego llamé a Measure and Arrange en el objeto de la grilla exterior para forzar un render sobre él. Vea aquí para saber cómo hacer eso. https://stackoverflow.com/a/4890217/2352625

Al forzar un render, tengo el tamaño real de cada celda que luego utilizo para crear las definiciones de fila y columna para mis encabezados (en lugar de establecerlos en Tamaño automático). Todavía no es perfecto, cuando se muestra una grilla grande, pero el desplazamiento es menor (unos pocos píxeles) en lugar de saltar por todos lados como estaba.