2017-10-12 3 views
3

J'utilise le GridHelper de Rachel Lim pour obtenir le nombre dynamique de lignes. Ce que je voulais réaliser, c'est que chaque ligne soit affichée en dessous d'une autre (finie), pour pouvoir les redimensionner (en utilisant GridSplitter) et que le contenu soit redimensionné proportionnellement à la taille de l'écran.ItemsControl - Redimensionnement automatique des éléments enfants

Résultat:

enter image description here

Ce que je voudrais avoir: enter image description here

Xaml:

<Grid> 
    <ItemsControl ItemsSource="{Binding RowSource}" > 
     <ItemsControl.ItemsPanel> 
      <ItemsPanelTemplate> 
       <Grid local:GridHelper.RowCount="{Binding RowCount}" /> 
      </ItemsPanelTemplate> 
     </ItemsControl.ItemsPanel> 
     <ItemsControl.ItemContainerStyle> 
      <Style TargetType="ContentPresenter"> 
       <Setter Property="Grid.Row" Value="{Binding RowNumber}"/> 
      </Style> 
     </ItemsControl.ItemContainerStyle> 
     <ItemsControl.ItemTemplate> 
      <DataTemplate> 
       <Grid> 
        <Grid.RowDefinitions> 
         <RowDefinition Height="Auto"/> 
         <RowDefinition Height="Auto"/> 
        </Grid.RowDefinitions> 
        <Grid> 
         <Grid.ColumnDefinitions> 
          <ColumnDefinition Width="*" /> 
          <ColumnDefinition Width="Auto" /> 
         </Grid.ColumnDefinitions> 
         <DataGrid> 
          <DataGrid.Columns> 
           <DataGridTextColumn Header="Col 1" /> 
           <DataGridTextColumn Header="Col 2" /> 
           <DataGridTextColumn Header="Col 3" /> 
          </DataGrid.Columns> 
         </DataGrid> 
         <Button Grid.Column="1" Content="Btn" /> 
        </Grid> 
        <GridSplitter Height="5" VerticalAlignment="Bottom" HorizontalAlignment="Stretch" Grid.Row="0" ResizeDirection="Rows" ResizeBehavior="CurrentAndNext"/> 
       </Grid> 
      </DataTemplate> 
     </ItemsControl.ItemTemplate> 
    </ItemsControl> 
</Grid> 

ViewModel:

internal class MyViewModel 
{ 
    public ObservableCollection<RowInfo> RowSource { get; set; } 

    public int RowCount { get { return RowSource.Count; } } 

    public MyViewModel() 
    { 
     RowSource = new ObservableCollection<RowInfo>() 
     { 
      new RowInfo() { RowNumber = 0 }, 
      new RowInfo() { RowNumber = 1 }, 
      new RowInfo() { RowNumber = 2 } 
     }; 
    } 
} 

rowInfo:

public class RowInfo 
{ 
    public int RowNumber { get; internal set; } 
} 
+0

Je ne suis pas sûr que je reçois bien la question, ce que vous voulez est que les lignes par défaut devraient avoir une certaine hauteur même si n'y a pas de contenu en eux. Est-ce que c'est le besoin? –

+0

Oui, je souhaite que les lignes soient redimensionnées proportionnellement à la taille de la fenêtre. @ mm8 a obtenu cette partie à droite mais le redimensionnement (avec GridSplitter) s'est arrêté pour fonctionner correctement. –

+0

Oh, donc, fondamentalement, vous voulez que le contenu soit réparti dans toute la vue et quand je redimensionne la fenêtre, vous voulez aussi mettre à l'échelle les lignes et les colonnes? –

Répondre

1

Je pense que votre approche est erronée. Vous ne pouvez pas utiliser un ItemsControl, car les éléments GridSplitter doivent être au niveau ItemsPanel plutôt que dans le DataTemplate - sinon, cela ne fonctionnera pas.

Vous feriez mieux d'utiliser un comportement personnalisé sur la grille elle-même - voir exemple de code ci-dessous:

public class GridAutoRowChildBehavior : Behavior<Grid> 
{ 
    public static readonly DependencyProperty ItemTemplateProperty = 
     DependencyProperty.Register("ItemTemplate", typeof(DataTemplate), typeof(GridAutoRowChildBehavior), 
      new PropertyMetadata(null, OnGridPropertyChanged)); 

    public static readonly DependencyProperty ItemsSourceProperty = 
     DependencyProperty.Register("ItemsSource", typeof(object), typeof(GridAutoRowChildBehavior), 
      new PropertyMetadata(null, OnGridPropertyChanged)); 

    private static void OnGridPropertyChanged(DependencyObject d, DependencyPropertyChangedEventArgs e) 
    { 
     ((GridAutoRowChildBehavior) d).ResetGrid(); 
    } 

    private void ResetGrid() 
    { 
     var source = ItemsSource as IEnumerable; 
     if (source == null || ItemTemplate == null) 
      return; 
     AssociatedObject.Children.Clear(); 
     AssociatedObject.RowDefinitions.Clear(); 
     var count = 0; 
     foreach (var item in source) 
     { 
      var content = new ContentPresenter 
      { 
       ContentTemplate = ItemTemplate, 
       Content = item 
      }; 
      var splitter = new GridSplitter 
      { 
       Height = 5, 
       VerticalAlignment = VerticalAlignment.Bottom, 
       HorizontalAlignment = HorizontalAlignment.Stretch 
      }; 
      AssociatedObject.RowDefinitions.Add(new RowDefinition { Height = new GridLength(1, GridUnitType.Star) }); 
      Grid.SetRow(content,count); 
      Grid.SetRow(splitter,count); 
      AssociatedObject.Children.Add(content); 
      AssociatedObject.Children.Add(splitter); 
      count++; 
     } 

    } 

    public DataTemplate ItemTemplate 
    { 
     get { return (DataTemplate) GetValue(ItemTemplateProperty); } 
     set { SetValue(ItemTemplateProperty, value); } 
    } 


    public object ItemsSource 
    { 
     get { return GetValue(ItemsSourceProperty); } 
     set { SetValue(ItemsSourceProperty, value); } 
    } 
} 

Ensuite, dans votre XAML vous coder comme ceci:

<Grid> 
    <i:Interaction.Behaviors> 
     <local:GridAutoRowChildBehavior ItemsSource="{Binding RowsSource}"> 
      <local:GridAutoRowChildBehavior.ItemTemplate> 
       <DataTemplate> 
        <Grid> 
         <Grid.ColumnDefinitions> 
          <ColumnDefinition Width="*" /> 
          <ColumnDefinition Width="Auto" /> 
         </Grid.ColumnDefinitions> 
         <DataGrid> 
          <DataGrid.Columns> 
           <DataGridTextColumn Header="Col 1" /> 
           <DataGridTextColumn Header="Col 2" /> 
           <DataGridTextColumn Header="Col 3" /> 
          </DataGrid.Columns> 
         </DataGrid> 
         <Button Grid.Column="1" Content="Btn" /> 
        </Grid> 
       </DataTemplate> 
      </local:GridAutoRowChildBehavior.ItemTemplate> 
     </local:GridAutoRowChildBehavior> 
    </i:Interaction.Behaviors> 
</Grid> 

J'ai testé ceci et cela fonctionne exactement comme vous avez besoin.

La seule chose supplémentaire que vous devez faire est d'ajouter le package Nuget Systems.Windows.Interactivity.WPF à votre projet

+0

Excellent travail Dean! Où puis-je en savoir plus sur la bibliothèque d'interactivité en profondeur? –

+0

c'est un bon point de départ https://msdn.microsoft.com/en-us/library/dn195669(v=vs.110).aspx –

+0

Juste une petite mise à jour pour quelqu'un qui pourrait lire ceci: si vous avez Behaviour à l'intérieur ItemControl (comme je l'ai mais ce n'est pas montré dans cet exemple), vous devez remplacer OnAttached et appeler ResetGrid à l'intérieur. protected override void OnAttached() { base.OnAttached(); ResetGrid(); } Vérifiez également si AssociatedObject est null à l'intérieur de la méthode ResetGrid. –

1

Utilisez étoile de calibrage pour la RowDefintions que vous avez créé dans la classe GridHelper:

public static void RowCountChanged(
    DependencyObject obj, DependencyPropertyChangedEventArgs e) 
{ 
    if (!(obj is Grid) || (int)e.NewValue < 0) 
     return; 

    Grid grid = (Grid)obj; 
    grid.RowDefinitions.Clear(); 

    for (int i = 0; i < (int)e.NewValue; i++) 
     grid.RowDefinitions.Add(
      new RowDefinition() { Height = new GridLength(1, GridUnitType.Star) }); //<-- 

    SetStarRows(grid); 
} 

et définissez les Height de votre premier RowDefinition à *:

<ItemsControl.ItemTemplate> 
    <DataTemplate> 
     <Grid Background="Yellow"> 
      <Grid.RowDefinitions> 
       <RowDefinition Height="*"/> 
       <RowDefinition Height="Auto"/> 
      </Grid.RowDefinitions> 
      <Grid> 
       <Grid.ColumnDefinitions> 
        <ColumnDefinition Width="*" /> 
        <ColumnDefinition Width="Auto" /> 
       </Grid.ColumnDefinitions> 
       <DataGrid> 
        <DataGrid.Columns> 
         <DataGridTextColumn Header="Col 1" /> 
         <DataGridTextColumn Header="Col 2" /> 
         <DataGridTextColumn Header="Col 3" /> 
        </DataGrid.Columns> 
       </DataGrid> 
       <Button Grid.Column="1" Content="Btn" /> 
      </Grid> 
      <GridSplitter Height="5" VerticalAlignment="Bottom" HorizontalAlignment="Stretch" Grid.Row="0" ResizeDirection="Rows" ResizeBehavior="CurrentAndNext"/> 
     </Grid> 
    </DataTemplate> 
</ItemsControl.ItemTemplate> 
+0

Cela fait redimensionner le contenu proportionnellement, mais le redimensionnement ne fonctionne pas correctement alors. –

+0

que voulez-vous dire par «redimensionnement»? – Iron

+0

Je souhaite utiliser GridSplitter pour redimensionner les lignes. –