2017-10-12 229 views
3

我使用Rachel Lim的GridHelper来获取动态行数。我想要实现的是让每行都显示为一个在另一个之下(完成),以便能够调整它们的大小(使用GridSplitter完成),并根据屏幕大小调整内容大小。ItemsControl - Grid子元素自动调整大小

结果:

enter image description here

我想什么有: 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> 

视图模型:

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

我不知道我得到的问题提得好,你要的是,默认情况下该行应该有一定的高度,即使有没有内容。那是什么需要? –

+0

是的,我希望行的大小按比例调整窗口大小。 @ mm8得到了正确的部分,但调整大小(与GridSplitter)停止正常工作。 –

+0

哦,所以基本上,你希望内容分布在整个视图中,当我调整窗口大小时,你还想缩放行和列? –

回答

1

我认为你的方法是错的。您不能使用ItemsControl,因为GridSplitter项目需要位于ItemsPanel级别,而不是DataTemplate - 否则,它将不起作用。

您最好使用对电网本身的自定义行为 - 见下面的示例代码:

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); } 
    } 
} 

然后在你的XAML你的代码它是这样的:

<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> 

我已经测试这和它的工作原理完全一样。

你需要做的唯一额外的事情是NuGet包Systems.Windows.Interactivity.WPF添加到您的项目

+0

伟大的工作院长!我在哪里可以深入了解更多关于交互性库的内容? –

+0

这是一个很好的起点https://msdn.microsoft.com/zh-cn/library/dn195669(v=vs.110).aspx –

+0

只是一个可能会读取此内容的人的小更新:如果您有内部行为ItemControl(就像我有,但没有在这个示例中显示),你必须重写OnAttached并在其中调用ResetGrid。 protected override void OnAttached() { base.OnAttached(); ResetGrid(); } 同时检查AssociatedObject在ResetGrid方法内是否为null。 –

1

使用星大小为您在GridHelper类创建的RowDefintions

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); 
} 

和设置您的第一RowDefinition*Height

<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

这确实会使内容按比例调整大小,但调整大小后无法正常工作。 –

+0

你是什么意思关于调整大小? – Iron

+0

我想使用GridSplitter来调整行的大小。 –