2012-01-14 11 views
6

Se si esegue la finestra di esempio sotto la parte superiore di ItemsControl si aggiornerà il layout per diversi secondi finché tutte le colonne avranno la larghezza corretta (corretta = identica alle colonne all'interno del lower ItemsControl).Le griglie con le colonne SharedSizeGroup si comportano in modo molto strano (* NON * ciclo infinito)

È possibile modificare la larghezza della finestra e scorrere gli oggetti in basso che circondano ScrollViewer sia orizzontalmente che verticalmente, ma non appena si modifica l'altezza della finestra, il layout si inverte per alcuni secondi.

Nota: non vi è alcuna ambiguità di ridimensionamento come in altre domande in cui la griglia aggiorna infinitamente le dimensioni.

Sto facendo qualcosa di sbagliato? E se sì, come potrei risolvere questo? - o dovrei inviare questo problema a Microsoft-Connect?

codice dietro:

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: Se si forza le voci del ItemsControl superiore di essere formato dare (con l'aggiunta di MinWidth="200" a GroupBox) quindi il lower ItemsControl agirà invece in modo sciocco.

BTW2: a partire da ca. 8 colonne di dimensioni condivise (nel campione ci sono 15, controllate da .Take(15)) si vede apparire il riarrangiamento e raddoppia nel tempo per ogni colonna aggiunta, quindi 20 colonne non si chiudono per minuti.

BTW3: Ricevere un singolo commento durante 3 mesi è molto frustrante.

risposta

2

Ben curiosamente ho fatto +1 su questa domanda tre mesi fa ma non ho risposto. Probabilmente la ragione per cui non hai ricevuto risposta è perché è difficile!

Io ancora non ho molto da dire oggi, se non che il layout WPF viene eseguita in due passaggi - misura e organizzare - e il successivo dimensionamento di elementi potrebbe innescare un layout su altri elementi ecc ...

In per dimensioni delle colonne correttamente WPF sta facendo qualcosa di simile:

  • colonna Misura 1 contenuti
  • Disporre colonna 1 contenuti
  • colonna Misura 2 contenuti
    • Attendere un sec, colonna 2 è maggiore del previsto
    • trigger una misura su tutti colonna 1 contenuti
      • Disporre colonna 1 contenuti
      • colonna Misura 2 contenuti

...ecc

Mi scuso per la mia visione semplicistica. Quante colonne hai (quindi numero di gruppi di dimensioni condivise)? Un'altra domanda. Che OS e .NET Framework stai usando? Ho sentito che c'era una limitazione al numero di SharedSizeGroups che potreste avere in WPF su WindowsXP, per esempio. Non sono sicuro se è stato corretto nei sistemi operativi successivi.

Come soluzione alternativa è possibile implementare questo comportamento da soli? Significato puoi creare la tua proprietà allegata che misura ogni elemento della griglia (tutte le colonne, tutte le righe) e imposta una volta le dimensioni di ciascuna colonna? A differenza di una colonna per base.

saluti,

+0

La quantità di colonne varia in fase di esecuzione. Sto usando .NET su W7. Non riesco a misurare tutte le colonne e tutte le righe perché uno dei 2 assi deve utilizzare un VirtualizedStackpanel. Forse dovrei scrivere il mio pannello usando la sua semantica SharedSize. Attualmente sto solo disabilitando l'assegnazione dei nomi SharedSizeGroup se ci sono più di 7 colonne. – springy76

+0

Sì, ci siamo appena imbattuti in questo. Abbiamo avuto 10 righe di gruppo condivise e ci sono voluti alcuni secondi prima che la dimensione si stabilizzasse dopo aver aggiunto un nuovo set di righe. Nel nostro caso sembrava che la maggior parte delle righe avessero effettivamente una dimensione fissa che poteva essere codificata nell'XAML. Una volta che il numero di gruppi condivisi è stato ridotto a 2 (questo era il numero che in realtà doveva essere dimensionato dinamicamente) il problema è andato via. Quindi sembra che tu abbia bisogno di usare questa proprietà con parsimonia. – briantyler

+0

Quello che non capisco è: la misura a 2 passaggi e il processo di arrangiamento normalmente avvengono senza cicli di verniciatura in mezzo. Se la tua finestra contiene troppi controlli, l'aggiornamento dell'interfaccia utente può essere ritardato per diversi secondi e l'intera app "sembra" essere congelata nel frattempo (il thread principale è davvero). – springy76

1

Ho avuto un problema simile. La mia situazione esatta è stata seguita da come l'ho risolto.

Ho una "griglia" costruita dove la riga superiore e la colonna sinistra rimangono sul posto mentre scorre il resto del contenuto (come celle di Excel congelate). La dimensione del contenuto varia e viene determinata in fase di esecuzione. Era anche difficile prevedere quale sarebbe stata la dimensione.

Per realizzare questo, ho un totale di 4 griglie - 1 griglia esterna per il layout e 3 griglie al suo interno- 1 per gli elementi di riga superiore, 1 per gli elementi di colonna di sinistra e 1 per il contenuto effettivo. Le righe della griglia del contenuto vengono sincronizzate con le righe della colonna di sinistra tramite un gruppo di dimensioni condivise e allo stesso modo con le colonne del contenuto e le colonne della riga superiore.

Per risolvere il problema, ho inserito per primi i dati della griglia effettiva nel codice sottostante. Quindi ho chiamato Measure e Arrange sull'oggetto grid esterno per forzare un rendering su di esso. Vedi qui per come farlo. https://stackoverflow.com/a/4890217/2352625

Forzando un rendering, ho le dimensioni effettive di ogni cella che uso quindi per creare le definizioni di righe e colonne per le intestazioni (anziché impostarle su Dimensioni automatiche). Non è ancora perfetto - quando visualizzo una grande griglia - ma lo spostamento è minore (pochi pixel) invece di saltare dappertutto come era.

Problemi correlati