如何创建可重用的 WPF 网格布局
Posted
技术标签:
【中文标题】如何创建可重用的 WPF 网格布局【英文标题】:How to create reusable WPF grid layout 【发布时间】:2011-02-22 10:52:57 【问题描述】:我有一个带有选项卡控件和页数的窗口 - 选项卡项。每个选项卡项具有相同的网格布局 - 6 行和 4 列。现在,每个选项卡项都包含带有行和列定义的网格,因此几乎一半的 XAML 是网格定义。
如何在一个地方定义此网格并在我的应用程序中重复使用该定义?模板?用户控制?
除了 6x4,我只有两个重复的网格尺寸:8x4 和 6x6。
编辑: 忘了提一下:每个选项卡的网格控件都不同。我只想在某些资源中定义一次网格,以便我可以在不同的标签页上重用它们。现在 XAML 看起来像这样:
<TabControl>
<TabItem Header="Property">
<Grid>
<Grid.RowDefinitions>
<RowDefinition />
<RowDefinition />
<RowDefinition />
<RowDefinition />
<RowDefinition />
<RowDefinition />
</Grid.RowDefinitions>
<Grid.ColumnDefinitions>
<ColumnDefinition />
<ColumnDefinition />
<ColumnDefinition />
<ColumnDefinition />
</Grid.ColumnDefinitions>
<!-- some controls here -->
</Grid>
</TabItem>
<TabItem Header="Style">
<Grid >
<Grid.RowDefinitions>
<RowDefinition />
<RowDefinition />
<RowDefinition />
<RowDefinition />
<RowDefinition />
<RowDefinition />
</Grid.RowDefinitions>
<Grid.ColumnDefinitions>
<ColumnDefinition />
<ColumnDefinition />
<ColumnDefinition />
<ColumnDefinition />
</Grid.ColumnDefinitions>
<!-- some controls here -->
</Grid>
</TabItem>
... and this repeats for several more tab items
</TabControl>
此网格定义对表单上的每个选项卡项重复。让我恼火的是 XAML 的一半是网格定义。
有没有办法在一个地方定义这个网格,然后重复使用这个定义?
【问题讨论】:
【参考方案1】:我认为最好的方法是使用ItemsControl
和ItemsPanelTemplate
,因为您需要一个容器来容纳多个项目:
<FrameworkElement.Resources>
<Style x:Key="GridItemsStyle"
TargetType="ItemsControl">
<Setter Property="ItemsPanel">
<Setter.Value>
<ItemsPanelTemplate>
<Grid>
<Grid.RowDefinitions>
<RowDefinition />
<RowDefinition />
<RowDefinition />
<RowDefinition />
<RowDefinition />
<RowDefinition />
</Grid.RowDefinitions>
<Grid.ColumnDefinitions>
<ColumnDefinition />
<ColumnDefinition />
<ColumnDefinition />
<ColumnDefinition />
</Grid.ColumnDefinitions>
</Grid>
</ItemsPanelTemplate>
</Setter.Value>
</Setter>
</Style>
</FrameworkElement.Resources>
<TabControl>
<TabItem>
<ItemsControl Style="StaticResource GridItemsStyle">
<TextBlock Grid.Row="1" Text="R1" />
<TextBlock Grid.Column="1"
Text="C1" />
</ItemsControl>
</TabItem>
<TabItem>
<ItemsControl Style="StaticResource GridItemsStyle">
<TextBlock Grid.Row="2"
Text="R2" />
<TextBlock Grid.Column="2"
Text="C2" />
</ItemsControl>
</TabItem>
</TabControl>
【讨论】:
看起来很简单 很好的答案!这正是我想要的,非常感谢分享:-)【参考方案2】:或者你可以从 Grid 继承...
using System.Windows.Controls;
public class AlreadySetupGrid:Grid
public AlreadySetupGrid()
for (int i = 0; i < 4; i++)
ColumnDefinitions.Add(new ColumnDefinition());
for (int i = 0; i < 6; i++)
RowDefinitions.Add(new RowDefinition());
然后使用它而不是您的普通网格。
【讨论】:
这听起来像是一个更好的计划,但这是我在设计时没有得到列和行。即网格中定义的任何元素都不会正确定位【参考方案3】:我有类似的东西。问题是您如何不将数据放入网格中?
当您一遍又一遍地使用相同的布局时,我猜您在每个单元格中放置了类似的东西。
我为每个选项卡创建了一个自定义 ItemsControl 以将数据放入其中,然后为显示网格的 ItemsControl 创建了一个样式。
<Style x:Key="GridItemsStyle"
TargetType="ItemsControl">
<Setter Property="ItemsPanel">
<Setter.Value>
<ControlTemplate>
<Grid>
<Grid.RowDefinitions>
<RowDefinition />
<RowDefinition />
<RowDefinition />
<RowDefinition />
<RowDefinition />
<RowDefinition />
</Grid.RowDefinitions>
<Grid.ColumnDefinitions>
<ColumnDefinition />
<ColumnDefinition />
<ColumnDefinition />
<ColumnDefinition />
</Grid.ColumnDefinitions>
<ContentPresenter Content="Binding ElementName=Cell00" Grid.Row="0" Grid.Column="0" />
<ContentPresenter Content="Binding ElementName=Cell01" Grid.Row="0" Grid.Column="1" />
<ContentPresenter Content="Binding ElementName=Cell10" Grid.Row="1" Grid.Column="0" />
<!-- ...And so on -->
</Grid>
</ControlTemplate>
</Setter.Value>
</Setter>
</Style>
在窗口中
<TabControl>
<TabItem>
<local:tab1 Style="StaticResource GridItemsStyle" />
</TabItem>
<TabItem>
<local:tab2 Style="StaticResource GridItemsStyle" />
</TabItem>
那么每个CustomControl都继承自ItemsControl
<ItemsControl x:Class="your_app.tab1"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:local="clr-namespace:your_app">
<ContentControl x:Name="Cell00">
<!-- Some stuff here -->
</ContentControl>
<ContentControl x:Name="Cell01">
<!-- Some stuff here -->
</ContentControl>
<ContentControl x:Name="Cell10">
<!-- Some stuff here -->
</ContentControl>
这与 Aelij 所做的非常相似,只是我设置了 ContentPresenter 并将其绑定到一个名称并将 itemsControl 放入它自己的东西中(您可以混合使用这两种解决方案)。
它仍然是很多代码,但我会说你一直保存自己所有的行和列定义,如果你必须修改它,你也只需要在一个地方更改网格。
【讨论】:
【参考方案4】:通常人们会为进入选项卡的数据编写一个 DataTemplate。该 DataTemplate 将包含网格。
【讨论】:
【参考方案5】:如何在一个地方定义此网格并在我的应用程序中重复使用该定义?模板?用户控制?
如果我是你,我会使用重复的代码创建一个 UserControl
或自定义 Control
,然后从当前代码中使用该控件。
另一种方法是使用DataTemplate
或ControlTemplate
。
为TabItem
s 创建一个ControlTemplate
也很有效。
【讨论】:
【参考方案6】:你可以做到,但需要一些工作:
1) 像这样创建一个集合和一个附加属性:
public class ColumnDefinitions : Collection<ColumnDefinition>
public static readonly DependencyProperty SourceProperty = DependencyProperty.RegisterAttached(
"Source",
typeof(ColumnDefinitions),
typeof(ColumnDefinitions),
new PropertyMetadata(
default(ColumnDefinitions),
OnColumnDefinitionsChanged));
public static void SetSource(Grid element, ColumnDefinitions value)
element.SetValue(SourceProperty, value);
[AttachedPropertyBrowsableForChildren(IncludeDescendants = false)]
[AttachedPropertyBrowsableForType(typeof(Grid))]
public static ColumnDefinitions GetSource(Grid element)
return (ColumnDefinitions)element.GetValue(SourceProperty);
private static void OnColumnDefinitionsChanged(DependencyObject d, DependencyPropertyChangedEventArgs e)
var grid = (Grid)d;
grid.ColumnDefinitions.Clear();
var columnDefinitions = (ColumnDefinitions)e.NewValue;
if (columnDefinitions == null)
return;
foreach (var columnDefinition in columnDefinitions)
grid.ColumnDefinitions.Add(columnDefinition);
2) 然后您可以将其用作资源和网格样式,如下所示:
请注意,必须使用x:Shared="False"
。如果不同,则会将相同的定义添加到许多导致 WPF 抛出的网格中。
<UserControl.Resources>
<demo:ColumnDefinitions x:Key="SomeColumnDefinitions" x:Shared="False">
<ColumnDefinition Width="Auto" />
<ColumnDefinition Width="*" />
</demo:ColumnDefinitions>
<Style x:Key="SomeGridStyle" TargetType="x:Type Grid">
<Setter Property="demo:ColumnDefinitions.Source" Value="StaticResource SomeColumnDefinitions"></Setter>
</Style>
</UserControl.Resources>
<Grid>
<Grid.RowDefinitions>
<RowDefinition />
<RowDefinition Height="5"/>
<RowDefinition />
</Grid.RowDefinitions>
<Grid Style="StaticResource SomeGridStyle">
<Rectangle Grid.Row="0"
Grid.Column="0"
Width="120"
Fill="Blue" />
<Rectangle Grid.Row="0"
Grid.Column="1"
Fill="Yellow" />
</Grid>
<Grid Grid.Row="2" demo:ColumnDefinitions.Source="StaticResource SomeColumnDefinitions">
<Rectangle Grid.Row="0"
Grid.Column="0"
Width="120"
Fill="Blue" />
<Rectangle Grid.Row="0"
Grid.Column="1"
Fill="Yellow" />
</Grid>
</Grid>
【讨论】:
以上是关于如何创建可重用的 WPF 网格布局的主要内容,如果未能解决你的问题,请参考以下文章
如何使用新的 CSS GRID 布局创建像 12 列(仅网格)网格系统的 Bootstrap