ItemsControl - 网格子元素自动调整大小
Posted
技术标签:
【中文标题】ItemsControl - 网格子元素自动调整大小【英文标题】:ItemsControl - Grid child elements auto resize 【发布时间】:2017-10-12 08:47:57 【问题描述】:我正在使用 Rachel Lim 的 GridHelper 来获取动态行数。我想要实现的是让每一行显示在另一行下方(完成),能够调整它们的大小(完成 - 使用 GridSplitter)并根据屏幕大小按比例调整内容大小。
结果:
我想要的:
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
;
行信息:
public class RowInfo
public int RowNumber get; internal set;
【问题讨论】:
我不确定我是否能很好地解决这个问题,您想要的是,即使其中没有内容,默认情况下行也应该有一定的高度。这就是需要吗? 是的,我希望行的大小与窗口大小成比例。 @mm8 得到了正确的部分,但调整大小(使用 GridSplitter)停止正常工作。 哦,基本上,您希望内容分布在整个视图中,当我调整窗口大小时,您还想缩放行和列? 没错。但我也想使用 GridSplitter 单独调整每一行的大小。 嗯,我明白了。我会试着写一个控件。 【参考方案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
添加到您的项目中
【讨论】:
干得好,院长!在哪里可以深入了解交互库? 这是一个很好的起点msdn.microsoft.com/en-us/library/dn195669(v=vs.110).aspx 对于可能会阅读此内容的人来说只是一个小更新:如果您在 ItemControl 中有 Behavior(就像我有,但在此示例中未显示),您必须覆盖 OnAttached 并在其中调用 ResetGrid。受保护的覆盖无效 OnAttached() base.OnAttached();重置网格();还要检查 ResetGrid 方法中的 AssociatedObject 是否为空。【参考方案2】:对您在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>
【讨论】:
这确实使内容按比例调整大小,但调整大小无法正常工作。resizing
是什么意思?
我想使用 GridSplitter 来调整行的大小。
我希望内容分布在整个视图中,当我调整窗口大小时,您也想缩放行和列。而且我还想使用 GridSplitter 单独调整每一行的大小。以上是关于ItemsControl - 网格子元素自动调整大小的主要内容,如果未能解决你的问题,请参考以下文章