响应式网格视图
Responsive GridView
我想为我的 Windows 通用应用程序创建响应式 GridView。我基本上想要一个 GridView,其中的列水平填充整个 space。
XAML应该是这样的,但我不知道我必须使用ItemsPanelTemplate的哪个组合。
<Page>
<Page.Resources>
<CollectionViewSource x:Name="groupedItemsViewSource" IsSourceGrouped="true"/>
</Page.Resources>
<GridView ItemsSource="{Binding Source={StaticResource groupedItemsViewSource}}">
<GridView.ItemsPanel>
<ItemsPanelTemplate>
<!-- ? -->
</ItemsPanelTemplate>
</GridView.ItemsPanel>
<GridView.GroupStyle>
<GroupStyle>
<GroupStyle.HeaderTemplate>
<DataTemplate>
<!-- header -->
</DataTemplate>
</GroupStyle.HeaderTemplate>
<GroupStyle.Panel>
<ItemsPanelTemplate>
<!-- ? -->
</ItemsPanelTemplate>
</GroupStyle.Panel>
</GroupStyle>
</GridView.GroupStyle>
<GridView.ItemTemplate>
<DataTemplate>
<!-- item -->
</DataTemplate>
</GridView.ItemTemplate>
</GridView>
</Page>
我明白你的问题了。老实说,您可能不会以这种方式结束。但也许你只是想学习如何去做。所以,为了学术探究,我将回答你的问题。
使用这个XAML:
<local:MyGridView>
<ItemsControl.ItemsPanel>
<ItemsPanelTemplate>
<Grid>
<Grid.RowDefinitions>
<RowDefinition />
<RowDefinition />
<RowDefinition />
</Grid.RowDefinitions>
<Grid.ColumnDefinitions>
<ColumnDefinition />
<ColumnDefinition />
<ColumnDefinition />
</Grid.ColumnDefinitions>
</Grid>
</ItemsPanelTemplate>
</ItemsControl.ItemsPanel>
<ItemsControl.ItemContainerStyle>
<Style TargetType="GridViewItem">
<Setter Property="HorizontalContentAlignment" Value="Stretch" />
<Setter Property="VerticalContentAlignment" Value="Stretch" />
</Style>
</ItemsControl.ItemContainerStyle>
<ItemsControl.ItemTemplate>
<DataTemplate>
<Grid Background="{Binding Color}"
Margin="10"
Grid.RowSpan="{Binding RowSpan}"
Grid.ColumnSpan="{Binding ColumnSpan}"
Grid.Row="{Binding Row}"
Grid.Column="{Binding Column}">
</Grid>
</DataTemplate>
</ItemsControl.ItemTemplate>
<GridView.Items>
<local:MyItem Color="Gainsboro" Row="0" RowSpan="1" Column="0" ColumnSpan="3" />
<local:MyItem Color="Red" Row="1" RowSpan="1" Column="0" ColumnSpan="1" />
<local:MyItem Color="Green" Row="1" RowSpan="1" Column="1" ColumnSpan="1" />
<local:MyItem Color="Blue" Row="1" RowSpan="1" Column="2" ColumnSpan="1" />
<local:MyItem Color="Yellow" Row="2" RowSpan="1" Column="0" ColumnSpan="1" />
<local:MyItem Color="Orange" Row="2" RowSpan="1" Column="1" ColumnSpan="1" />
</GridView.Items>
</local:MyGridView>
后面使用这段代码:
public class MyGridView : GridView
{
protected override DependencyObject GetContainerForItemOverride()
{
var container = base.GetContainerForItemOverride() as FrameworkElement;
if (container == null) return container;
var content = ItemTemplate.LoadContent() as FrameworkElement;
if (content == null) return container;
// sync the container grid dependency properties with the content
var binding = content.GetBindingExpression(Grid.RowProperty);
if (binding != null)
container.SetBinding(Grid.RowProperty, content.GetBindingExpression(Grid.RowProperty).ParentBinding);
binding = content.GetBindingExpression(Grid.RowSpanProperty);
if (binding != null)
container.SetBinding(Grid.RowSpanProperty, binding.ParentBinding);
binding = content.GetBindingExpression(Grid.ColumnProperty);
if (binding != null)
container.SetBinding(Grid.ColumnProperty, binding.ParentBinding);
binding = content.GetBindingExpression(Grid.ColumnSpanProperty);
if (binding != null)
container.SetBinding(Grid.ColumnSpanProperty, binding.ParentBinding);
return container;
}
}
这将准确地给出您在问题中所要求的内容。
现在,我们来谈谈您可能不想要这种方法的原因。单元格的动态大小不是 WrapGrid
的功能,GridView
的原生面板。因此,我们必须切换到 Grid
,它没有动态 Rows/Columns。我可以更新此示例以创建动态 Rows/Columns 吗?当然。但这不是重点。
在内部,MS Design 建议您根据 GridView
的宽度略微更改页边距。这本身就是一个不小的壮举,因为您无法将数据绑定到边距。但最终的视觉效果实际上得到了很大改善,因为随着宽度的减小,它在页面上提供了更多 space,而不会弄乱数据项的大小。一旦达到一定的窄宽度,您就可以让本机 WrapGrid
为您删除列,而不是保持固定数量的列。
退后一步,考虑如何使用初始方法使用自适应逻辑编写 GridView
中的每个数据项。这种复杂性对大多数应用程序来说都是不必要的补充。话虽如此,我并不像您那样了解您的应用程序。你是开发者而不是我。您可以决定什么最适合您的项目。
您可能会问自己,Microsoft 如何改变利润率?答案是使用 VSM 我们等待特定的宽度,当它出现时,我们明确地设置边距。根据您决定使用的控件类型,您可能需要以某种方式注入边距,但一般来说,这只是一个 VSM 操作。这很重要,因为它不是滑动尺度。也就是说,它要么是更宽的边距,要么是更窄的边距,没有中间值。
伙计,我希望这是有道理的。
祝你好运!
我想为我的 Windows 通用应用程序创建响应式 GridView。我基本上想要一个 GridView,其中的列水平填充整个 space。
XAML应该是这样的,但我不知道我必须使用ItemsPanelTemplate的哪个组合。
<Page>
<Page.Resources>
<CollectionViewSource x:Name="groupedItemsViewSource" IsSourceGrouped="true"/>
</Page.Resources>
<GridView ItemsSource="{Binding Source={StaticResource groupedItemsViewSource}}">
<GridView.ItemsPanel>
<ItemsPanelTemplate>
<!-- ? -->
</ItemsPanelTemplate>
</GridView.ItemsPanel>
<GridView.GroupStyle>
<GroupStyle>
<GroupStyle.HeaderTemplate>
<DataTemplate>
<!-- header -->
</DataTemplate>
</GroupStyle.HeaderTemplate>
<GroupStyle.Panel>
<ItemsPanelTemplate>
<!-- ? -->
</ItemsPanelTemplate>
</GroupStyle.Panel>
</GroupStyle>
</GridView.GroupStyle>
<GridView.ItemTemplate>
<DataTemplate>
<!-- item -->
</DataTemplate>
</GridView.ItemTemplate>
</GridView>
</Page>
我明白你的问题了。老实说,您可能不会以这种方式结束。但也许你只是想学习如何去做。所以,为了学术探究,我将回答你的问题。
使用这个XAML:
<local:MyGridView>
<ItemsControl.ItemsPanel>
<ItemsPanelTemplate>
<Grid>
<Grid.RowDefinitions>
<RowDefinition />
<RowDefinition />
<RowDefinition />
</Grid.RowDefinitions>
<Grid.ColumnDefinitions>
<ColumnDefinition />
<ColumnDefinition />
<ColumnDefinition />
</Grid.ColumnDefinitions>
</Grid>
</ItemsPanelTemplate>
</ItemsControl.ItemsPanel>
<ItemsControl.ItemContainerStyle>
<Style TargetType="GridViewItem">
<Setter Property="HorizontalContentAlignment" Value="Stretch" />
<Setter Property="VerticalContentAlignment" Value="Stretch" />
</Style>
</ItemsControl.ItemContainerStyle>
<ItemsControl.ItemTemplate>
<DataTemplate>
<Grid Background="{Binding Color}"
Margin="10"
Grid.RowSpan="{Binding RowSpan}"
Grid.ColumnSpan="{Binding ColumnSpan}"
Grid.Row="{Binding Row}"
Grid.Column="{Binding Column}">
</Grid>
</DataTemplate>
</ItemsControl.ItemTemplate>
<GridView.Items>
<local:MyItem Color="Gainsboro" Row="0" RowSpan="1" Column="0" ColumnSpan="3" />
<local:MyItem Color="Red" Row="1" RowSpan="1" Column="0" ColumnSpan="1" />
<local:MyItem Color="Green" Row="1" RowSpan="1" Column="1" ColumnSpan="1" />
<local:MyItem Color="Blue" Row="1" RowSpan="1" Column="2" ColumnSpan="1" />
<local:MyItem Color="Yellow" Row="2" RowSpan="1" Column="0" ColumnSpan="1" />
<local:MyItem Color="Orange" Row="2" RowSpan="1" Column="1" ColumnSpan="1" />
</GridView.Items>
</local:MyGridView>
后面使用这段代码:
public class MyGridView : GridView
{
protected override DependencyObject GetContainerForItemOverride()
{
var container = base.GetContainerForItemOverride() as FrameworkElement;
if (container == null) return container;
var content = ItemTemplate.LoadContent() as FrameworkElement;
if (content == null) return container;
// sync the container grid dependency properties with the content
var binding = content.GetBindingExpression(Grid.RowProperty);
if (binding != null)
container.SetBinding(Grid.RowProperty, content.GetBindingExpression(Grid.RowProperty).ParentBinding);
binding = content.GetBindingExpression(Grid.RowSpanProperty);
if (binding != null)
container.SetBinding(Grid.RowSpanProperty, binding.ParentBinding);
binding = content.GetBindingExpression(Grid.ColumnProperty);
if (binding != null)
container.SetBinding(Grid.ColumnProperty, binding.ParentBinding);
binding = content.GetBindingExpression(Grid.ColumnSpanProperty);
if (binding != null)
container.SetBinding(Grid.ColumnSpanProperty, binding.ParentBinding);
return container;
}
}
这将准确地给出您在问题中所要求的内容。
现在,我们来谈谈您可能不想要这种方法的原因。单元格的动态大小不是 WrapGrid
的功能,GridView
的原生面板。因此,我们必须切换到 Grid
,它没有动态 Rows/Columns。我可以更新此示例以创建动态 Rows/Columns 吗?当然。但这不是重点。
在内部,MS Design 建议您根据 GridView
的宽度略微更改页边距。这本身就是一个不小的壮举,因为您无法将数据绑定到边距。但最终的视觉效果实际上得到了很大改善,因为随着宽度的减小,它在页面上提供了更多 space,而不会弄乱数据项的大小。一旦达到一定的窄宽度,您就可以让本机 WrapGrid
为您删除列,而不是保持固定数量的列。
退后一步,考虑如何使用初始方法使用自适应逻辑编写 GridView
中的每个数据项。这种复杂性对大多数应用程序来说都是不必要的补充。话虽如此,我并不像您那样了解您的应用程序。你是开发者而不是我。您可以决定什么最适合您的项目。
您可能会问自己,Microsoft 如何改变利润率?答案是使用 VSM 我们等待特定的宽度,当它出现时,我们明确地设置边距。根据您决定使用的控件类型,您可能需要以某种方式注入边距,但一般来说,这只是一个 VSM 操作。这很重要,因为它不是滑动尺度。也就是说,它要么是更宽的边距,要么是更窄的边距,没有中间值。
伙计,我希望这是有道理的。
祝你好运!