当还有额外的 space 剩余时,如何填充 ItemsControl 的一行?
How to fill a row of an ItemsControl when there is still an extra space remaining?
我的目标是在 ItemsControl
中显示我的数据时有 3 列 。我发现关于这个问题的大部分答案都是使用 UniformGrid
。像这样:
<ItemsControl x:Name="Tasks"
ItemsSource="{Binding Tasks}">
<ItemsControl.ItemsPanel>
<ItemsPanelTemplate>
<UniformGrid Columns="3"
Background="Green" />
</ItemsPanelTemplate>
</ItemsControl.ItemsPanel>
<ItemsControl.ItemTemplate>
<DataTemplate>
<Button Margin="0,10,0,16"
Padding="18,5,18,11"
Height="153"
Width="192"
Background="{StaticResource Card}"
Style="{StaticResource PlainButtonTheme}">
<!--Button Content-->
</Button>
</DataTemplate>
</ItemsControl.ItemTemplate>
</ItemsControl>
我的 UI 现在看起来像这样(我只是添加了绿色背景,所以我可以看到整个 UniformGrid):
我在这里想要的是我的中间列来占据整个 space(有点像网格的 * 行为)。我怎样才能做到这一点?
I tried using Grid before I used UniformGrid but my child controls just get stacked on top on each other, so after rendering I can only see one control.
需要明确设置单元格的地址(行和列)。
示例:
namespace GridItems
{
public class TileData
{
public object Content { get; set; }
public int Row { get; set; }
public int Column { get; set; }
public TileData() { }
public TileData(object content, int row, int column)
{
Content = content;
Row = row;
Column = column;
}
}
}
namespace GridItems
{
public class TilesViewModel
{
public TileData[] Tiles { get; } =
{
new TileData("First", 0, 0),
new TileData("Second", 0, 1),
new TileData("Third", 0, 2),
new TileData("Fourth", 1, 0),
new TileData("Fifth", 1, 1),
new TileData("Sixth", 1, 2)
};
}
}
<Window x:Class="GridItems.GridItemsWindow"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
xmlns:local="clr-namespace:GridItems"
mc:Ignorable="d"
Title="GridItemsWindow" Height="450" Width="800">
<FrameworkElement.DataContext>
<local:TilesViewModel/>
</FrameworkElement.DataContext>
<FrameworkElement.Resources>
<DataTemplate x:Key="TileTemplate" DataType="local:TileData">
<Viewbox Margin="20">
<TextBlock Text="{Binding Content}"
FontSize="20"
Padding="20"
Background="Aqua"/>
</Viewbox>
</DataTemplate>
<Style x:Key="ItemStyle" TargetType="ContentPresenter">
<Setter Property="Grid.Row" Value="{Binding Row}"/>
<Setter Property="Grid.Column" Value="{Binding Column}"/>
</Style>
<ItemsPanelTemplate x:Key="GridTemplate">
<Grid>
<Grid.ColumnDefinitions>
<ColumnDefinition Width="100"/>
<ColumnDefinition />
<ColumnDefinition Width="100"/>
</Grid.ColumnDefinitions>
<Grid.RowDefinitions>
<RowDefinition/>
<RowDefinition/>
</Grid.RowDefinitions>
</Grid>
</ItemsPanelTemplate>
</FrameworkElement.Resources>
<Grid>
<ItemsControl ItemsSource="{Binding Tiles}"
ItemTemplate="{DynamicResource TileTemplate}"
ItemContainerStyle="{DynamicResource ItemStyle}"
ItemsPanel="{DynamicResource GridTemplate}"/>
</Grid>
</Window>
补充:回答关于动态改变collection中元素数量的问题,相应地,Grid行。
使用附加的实施选项 属性。
using System;
using System.Windows;
using System.Windows.Controls;
namespace GridItems
{
public static class AutoRowsGrid
{
/// <summary> Returns the value of the ChildrenCount attached property for <paramref name = "grid" />. </summary>
/// <param name = "grid"> <see cref = "Grid" /> whose property value will be returned. </param>
/// <returns> <see cref = "int" /> property value. </returns>
public static int? GetChildrenCount(Grid grid)
{
return (int?)grid.GetValue(ChildrenCountProperty);
}
/// <summary> Sets the ChildrenCount attached property for <paramref name = "grid" />. </summary>
/// <param name = "grid"> <see cref = "Grid" /> whose property value will be returned. </param>
/// <param name = "value"> <see cref = "int" /> value for the property. </param>
public static void SetChildrenCount(Grid grid, int value)
{
grid.SetValue(ChildrenCountProperty, value);
}
/// <summary><see cref="DependencyProperty"/> for methods <see cref="GetChildrenCount(Grid)"/> и <see cref="SetChildrenCount(Grid, int)"/>.</summary>
public static readonly DependencyProperty ChildrenCountProperty =
DependencyProperty.RegisterAttached(nameof(GetChildrenCount).Substring(3), typeof(int?), typeof(AutoRowsGrid), new PropertyMetadata(null, CountChanged));
private static void CountChanged(DependencyObject d, DependencyPropertyChangedEventArgs e)
{
Grid grid = (Grid)d;
double count = (int)e.NewValue;
int columns = grid.ColumnDefinitions.Count;
if (columns < 1)
columns = 1;
int newRows = (int)Math.Ceiling(count / columns);
int rows = grid.RowDefinitions.Count;
if (newRows != rows)
{
if (newRows > rows)
{
for (; newRows > rows; rows++)
{
grid.RowDefinitions.Add(new RowDefinition());
}
}
else
{
for (rows--; newRows <= rows; rows--)
{
grid.RowDefinitions.RemoveAt(rows);
}
}
}
}
}
}
<Window x:Class="GridItems.GridItemsWindow"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
xmlns:local="clr-namespace:GridItems"
mc:Ignorable="d"
Title="GridItemsWindow" Height="450" Width="800">
<FrameworkElement.DataContext>
<local:TilesViewModel/>
</FrameworkElement.DataContext>
<FrameworkElement.Resources>
<DataTemplate x:Key="TileTemplate" DataType="local:TileData">
<Viewbox Margin="20">
<TextBlock Text="{Binding Content}"
FontSize="20"
Padding="20"
Background="Aqua"/>
</Viewbox>
</DataTemplate>
<Style x:Key="ItemStyle" TargetType="ContentPresenter">
<Setter Property="Grid.Row" Value="{Binding Row}"/>
<Setter Property="Grid.Column" Value="{Binding Column}"/>
</Style>
<ItemsPanelTemplate x:Key="GridTemplate">
<Grid local:AutoRowsGrid.ChildrenCount="{Binding Items.Count, ElementName=listBox}">
<Grid.ColumnDefinitions>
<ColumnDefinition Width="100"/>
<ColumnDefinition />
<ColumnDefinition Width="100"/>
</Grid.ColumnDefinitions>
</Grid>
</ItemsPanelTemplate>
</FrameworkElement.Resources>
<Grid>
<ItemsControl x:Name="listBox"
ItemsSource="{Binding Tiles}"
ItemTemplate="{DynamicResource TileTemplate}"
ItemContainerStyle="{DynamicResource ItemStyle}"
ItemsPanel="{DynamicResource GridTemplate}"/>
</Grid>
</Window>
但如果你做得“相当正确”,那么在你的collection中,它的元素就会有明显的异质性。
左列、中列和右列的项目需要不同的呈现方式。
因此,最正确的,基于OOP的原则,是创建一个包含一行所有元素的类型,然后用行填充collection,而不是单独的单元格。
我的目标是在 ItemsControl
中显示我的数据时有 3 列 。我发现关于这个问题的大部分答案都是使用 UniformGrid
。像这样:
<ItemsControl x:Name="Tasks"
ItemsSource="{Binding Tasks}">
<ItemsControl.ItemsPanel>
<ItemsPanelTemplate>
<UniformGrid Columns="3"
Background="Green" />
</ItemsPanelTemplate>
</ItemsControl.ItemsPanel>
<ItemsControl.ItemTemplate>
<DataTemplate>
<Button Margin="0,10,0,16"
Padding="18,5,18,11"
Height="153"
Width="192"
Background="{StaticResource Card}"
Style="{StaticResource PlainButtonTheme}">
<!--Button Content-->
</Button>
</DataTemplate>
</ItemsControl.ItemTemplate>
</ItemsControl>
我的 UI 现在看起来像这样(我只是添加了绿色背景,所以我可以看到整个 UniformGrid):
我在这里想要的是我的中间列来占据整个 space(有点像网格的 * 行为)。我怎样才能做到这一点?
I tried using Grid before I used UniformGrid but my child controls just get stacked on top on each other, so after rendering I can only see one control.
需要明确设置单元格的地址(行和列)。
示例:
namespace GridItems
{
public class TileData
{
public object Content { get; set; }
public int Row { get; set; }
public int Column { get; set; }
public TileData() { }
public TileData(object content, int row, int column)
{
Content = content;
Row = row;
Column = column;
}
}
}
namespace GridItems
{
public class TilesViewModel
{
public TileData[] Tiles { get; } =
{
new TileData("First", 0, 0),
new TileData("Second", 0, 1),
new TileData("Third", 0, 2),
new TileData("Fourth", 1, 0),
new TileData("Fifth", 1, 1),
new TileData("Sixth", 1, 2)
};
}
}
<Window x:Class="GridItems.GridItemsWindow"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
xmlns:local="clr-namespace:GridItems"
mc:Ignorable="d"
Title="GridItemsWindow" Height="450" Width="800">
<FrameworkElement.DataContext>
<local:TilesViewModel/>
</FrameworkElement.DataContext>
<FrameworkElement.Resources>
<DataTemplate x:Key="TileTemplate" DataType="local:TileData">
<Viewbox Margin="20">
<TextBlock Text="{Binding Content}"
FontSize="20"
Padding="20"
Background="Aqua"/>
</Viewbox>
</DataTemplate>
<Style x:Key="ItemStyle" TargetType="ContentPresenter">
<Setter Property="Grid.Row" Value="{Binding Row}"/>
<Setter Property="Grid.Column" Value="{Binding Column}"/>
</Style>
<ItemsPanelTemplate x:Key="GridTemplate">
<Grid>
<Grid.ColumnDefinitions>
<ColumnDefinition Width="100"/>
<ColumnDefinition />
<ColumnDefinition Width="100"/>
</Grid.ColumnDefinitions>
<Grid.RowDefinitions>
<RowDefinition/>
<RowDefinition/>
</Grid.RowDefinitions>
</Grid>
</ItemsPanelTemplate>
</FrameworkElement.Resources>
<Grid>
<ItemsControl ItemsSource="{Binding Tiles}"
ItemTemplate="{DynamicResource TileTemplate}"
ItemContainerStyle="{DynamicResource ItemStyle}"
ItemsPanel="{DynamicResource GridTemplate}"/>
</Grid>
</Window>
补充:回答关于动态改变collection中元素数量的问题,相应地,Grid行。
使用附加的实施选项 属性。
using System;
using System.Windows;
using System.Windows.Controls;
namespace GridItems
{
public static class AutoRowsGrid
{
/// <summary> Returns the value of the ChildrenCount attached property for <paramref name = "grid" />. </summary>
/// <param name = "grid"> <see cref = "Grid" /> whose property value will be returned. </param>
/// <returns> <see cref = "int" /> property value. </returns>
public static int? GetChildrenCount(Grid grid)
{
return (int?)grid.GetValue(ChildrenCountProperty);
}
/// <summary> Sets the ChildrenCount attached property for <paramref name = "grid" />. </summary>
/// <param name = "grid"> <see cref = "Grid" /> whose property value will be returned. </param>
/// <param name = "value"> <see cref = "int" /> value for the property. </param>
public static void SetChildrenCount(Grid grid, int value)
{
grid.SetValue(ChildrenCountProperty, value);
}
/// <summary><see cref="DependencyProperty"/> for methods <see cref="GetChildrenCount(Grid)"/> и <see cref="SetChildrenCount(Grid, int)"/>.</summary>
public static readonly DependencyProperty ChildrenCountProperty =
DependencyProperty.RegisterAttached(nameof(GetChildrenCount).Substring(3), typeof(int?), typeof(AutoRowsGrid), new PropertyMetadata(null, CountChanged));
private static void CountChanged(DependencyObject d, DependencyPropertyChangedEventArgs e)
{
Grid grid = (Grid)d;
double count = (int)e.NewValue;
int columns = grid.ColumnDefinitions.Count;
if (columns < 1)
columns = 1;
int newRows = (int)Math.Ceiling(count / columns);
int rows = grid.RowDefinitions.Count;
if (newRows != rows)
{
if (newRows > rows)
{
for (; newRows > rows; rows++)
{
grid.RowDefinitions.Add(new RowDefinition());
}
}
else
{
for (rows--; newRows <= rows; rows--)
{
grid.RowDefinitions.RemoveAt(rows);
}
}
}
}
}
}
<Window x:Class="GridItems.GridItemsWindow"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
xmlns:local="clr-namespace:GridItems"
mc:Ignorable="d"
Title="GridItemsWindow" Height="450" Width="800">
<FrameworkElement.DataContext>
<local:TilesViewModel/>
</FrameworkElement.DataContext>
<FrameworkElement.Resources>
<DataTemplate x:Key="TileTemplate" DataType="local:TileData">
<Viewbox Margin="20">
<TextBlock Text="{Binding Content}"
FontSize="20"
Padding="20"
Background="Aqua"/>
</Viewbox>
</DataTemplate>
<Style x:Key="ItemStyle" TargetType="ContentPresenter">
<Setter Property="Grid.Row" Value="{Binding Row}"/>
<Setter Property="Grid.Column" Value="{Binding Column}"/>
</Style>
<ItemsPanelTemplate x:Key="GridTemplate">
<Grid local:AutoRowsGrid.ChildrenCount="{Binding Items.Count, ElementName=listBox}">
<Grid.ColumnDefinitions>
<ColumnDefinition Width="100"/>
<ColumnDefinition />
<ColumnDefinition Width="100"/>
</Grid.ColumnDefinitions>
</Grid>
</ItemsPanelTemplate>
</FrameworkElement.Resources>
<Grid>
<ItemsControl x:Name="listBox"
ItemsSource="{Binding Tiles}"
ItemTemplate="{DynamicResource TileTemplate}"
ItemContainerStyle="{DynamicResource ItemStyle}"
ItemsPanel="{DynamicResource GridTemplate}"/>
</Grid>
</Window>
但如果你做得“相当正确”,那么在你的collection中,它的元素就会有明显的异质性。
左列、中列和右列的项目需要不同的呈现方式。
因此,最正确的,基于OOP的原则,是创建一个包含一行所有元素的类型,然后用行填充collection,而不是单独的单元格。