WPF: 带有列/行边距/填充的网格?

在 WPF 网格中为行或列指定边距和/或填充是否容易?

当然,我可以添加额外的列来填充空格,但这似乎是一项填充/边距的工作(它将使 很多的 XAML 更简单)。是否有人从标准网格派生出来添加此功能?

211051 次浏览

RowDefinitionColumnDefinitionContentElement类型,而 Margin严格来说是 FrameworkElement属性。因此,对于你的问题,“是否容易实现”的答案是一个非常明确的否定。没有,我没有看到任何布局面板演示这种功能。

您可以按照建议添加额外的行或列。但是您也可以在 Grid元素本身上设置边距,或者在 Grid中设置任何边距,所以这是目前最好的解决方案。

您可以编写自己的从 Grid继承的 GridWithMargin类,并重写 ArrangeOverride方法以应用边距

一种可能性是添加固定宽度的行和列,作为您正在寻找的填充/边距。

您可能还会考虑到您受到容器大小的限制,网格将变得与包含元素或其指定的宽度和高度一样大。您可以简单地使用不设置宽度或高度的列和行。这样,它们默认均匀地分割网格中的总空间。然后它将只是一个问题,集中您的元素垂直和水平在您的网格。

另一种方法可能是将所有网格元素包装在一个固定的、具有固定大小和边距的单行和单列网格中。网格包含固定宽度/高度的框,其中包含实际元素。

你可以用这样的东西:

<Style TargetType="{x:Type DataGridCell}">
<Setter Property="Padding" Value="4" />
<Setter Property="Template">
<Setter.Value>
<ControlTemplate TargetType="{x:Type DataGridCell}">
<Border Padding="{TemplateBinding Padding}" BorderBrush="{TemplateBinding BorderBrush}" BorderThickness="{TemplateBinding BorderThickness}" Background="{TemplateBinding Background}" SnapsToDevicePixels="True">
<ContentPresenter SnapsToDevicePixels="{TemplateBinding SnapsToDevicePixels}"/>
</Border>
</ControlTemplate>
</Setter.Value>
</Setter>

或者如果你不需要 TemplateBindings:

<Style TargetType="{x:Type DataGridCell}">
<Setter Property="Template">
<Setter.Value>
<ControlTemplate TargetType="{x:Type DataGridCell}">
<Border Padding="4">
<ContentPresenter />
</Border>
</ControlTemplate>
</Setter.Value>
</Setter>
</Style>

我现在就用我的一个坐标做到了。

  • 首先对网格中的每个元素应用相同的边距。您可以使用样式或任何您喜欢的方式手动执行此操作。假设你想要一个6px 的水平间距和一个2px 的垂直间距。然后向网格的每个子元素添加“3px 1px”的边距。
  • 然后删除在网格周围创建的边距(如果要将网格内控件的边框对齐到网格的相同位置)。这样设置网格的边距为“ -3px -1 px”。这样,网格外部的其他控件将与网格内部的最外部控件对。

在单元格控件之外使用 Border控件并为其定义填充:

    <Grid>
<Grid.Resources >
<Style TargetType="Border" >
<Setter Property="Padding" Value="5,5,5,5" />
</Style>
</Grid.Resources>


<Grid.RowDefinitions>
<RowDefinition/>
<RowDefinition/>
</Grid.RowDefinitions>


<Border Grid.Row="0" Grid.Column="0">
<YourGridControls/>
</Border>
<Border Grid.Row="1" Grid.Column="0">
<YourGridControls/>
</Border>


</Grid>


来源:

我最近在开发一些软件的时候遇到了这个问题,我突然想问为什么?他们为什么要这么做... 答案就在我眼前。一行数据是一个对象,因此如果我们保持面向对象,那么特定行的设计应该分开(假设以后需要重用行显示)。因此,我开始使用数据绑定堆栈面板和自定义控件来显示大多数数据。列表偶尔会出现,但大多数情况下网格只用于主页面组织(页眉、菜单区域、内容区域、其他区域)。自定义对象可以轻松地管理堆栈面板或网格中每一行的任何间距要求(单个网格单元格可以包含整个行对象)。这样做还有一个额外的好处,就是可以对方向的变化、扩展/塌陷等做出正确的反应。

<Grid>
<Grid.RowDefinitions>
<RowDefinition />
<RowDefinition />
</Grid.RowDefinitions>


<custom:MyRowObject Style="YourStyleHereOrGeneralSetter" Grid.Row="0" />
<custom:MyRowObject Style="YourStyleHere" Grid.Row="1" />
</Grid>

或者

<StackPanel>
<custom:MyRowObject Style="YourStyleHere" Grid.Row="0" />
<custom:MyRowObject Style="YourStyleHere" Grid.Row="1" />
</StackPanel>

如果您使用数据绑定,则 Custom 控件也将继承 DataContext... 这种方法的个人最喜欢的好处。

虽然不能向 Grid 添加边距或填充,但可以使用 Frame (或类似的容器)之类的东西,可以将其应用到其中。

这样(如果你在按钮上点击显示或隐藏控件,比如说) ,你就不需要在每个可能与之交互的控件上添加边距。

可以将其看作是将控件组隔离为单元,然后对这些单元应用样式。

我想我应该加上我自己的解决方案,因为还没有人提到这一点。您可以使用样式声明来定位包含在网格中的控件,而不是设计基于 Grid 的 UserControl。在不为每个元素定义的情况下,为所有元素添加空白/边距,这是非常麻烦和劳动密集型的。例如,如果您的 Grid 只包含 TextBlock,您可以这样做:

<Style TargetType="{x:Type TextBlock}">
<Setter Property="Margin" Value="10"/>
</Style>

这就相当于“细胞填充”。

有时候简单的方法是最好的。用空格填充你的字符串。如果它只是几个文本框等,这是迄今为止最简单的方法。

您也可以简单地插入具有固定大小的空白列/行。

如创建 GridWithMargins 类之前所述。 下面是我的工作代码示例

public class GridWithMargins : Grid
{
public Thickness RowMargin { get; set; } = new Thickness(10, 10, 10, 10);
protected override Size ArrangeOverride(Size arrangeSize)
{
var basesize = base.ArrangeOverride(arrangeSize);


foreach (UIElement child in InternalChildren)
{
var pos = GetPosition(child);
pos.X += RowMargin.Left;
pos.Y += RowMargin.Top;


var actual = child.RenderSize;
actual.Width -= (RowMargin.Left + RowMargin.Right);
actual.Height -= (RowMargin.Top + RowMargin.Bottom);
var rec = new Rect(pos, actual);
child.Arrange(rec);
}
return arrangeSize;
}


private Point GetPosition(Visual element)
{
var posTransForm = element.TransformToAncestor(this);
var areaTransForm = posTransForm.Transform(new Point(0, 0));
return areaTransForm;
}
}

用法:

<Window x:Class="WpfApplication1.MainWindow"
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:WpfApplication1"
mc:Ignorable="d"
Title="MainWindow" Height="350" Width="525">
<Grid>
<local:GridWithMargins ShowGridLines="True">
<Grid.RowDefinitions>
<RowDefinition />
<RowDefinition />
<RowDefinition />
<RowDefinition />
<RowDefinition />
</Grid.RowDefinitions>
<Grid.ColumnDefinitions>
<ColumnDefinition />
<ColumnDefinition />
<ColumnDefinition />
</Grid.ColumnDefinitions>
<Rectangle Fill="Red" Grid.Row="0" Grid.Column="0" HorizontalAlignment="Stretch" VerticalAlignment="Stretch" />
<Rectangle Fill="Green" Grid.Row="1" Grid.Column="0" HorizontalAlignment="Stretch" VerticalAlignment="Stretch" />
<Rectangle Fill="Blue" Grid.Row="1" Grid.Column="1" HorizontalAlignment="Stretch" VerticalAlignment="Stretch" />
</local:GridWithMargins>
</Grid>
</Window>

(Windows10FallCreatorsUpdate 版本及以上)

<Grid RowSpacing="3" ColumnSpacing="3">

我很惊讶我还没有看到这个解决方案发布。

来自 web 的引导框架(如 bootstrap)将使用负边距来拉回行/列。

它可能有点冗长(尽管没有那么糟糕) ,它确实可以工作,而且元素的间隔和大小都是均匀的。

在下面的例子中,我使用了一个 StackPanel根来演示如何使用边距均匀地分隔3个按钮。您可以使用其他元素,只需将内部的 x: Type 从按钮更改为您的元素。

这个想法很简单,在外部使用一个网格将元素的边距拉出内部网格边界的一半(使用负边距) ,使用内部网格将元素的间距均匀地拉出你想要的数量。

更新: 一个用户的评论说它不起作用,这里有一个快速的视频演示: < a href = “ https://youtu.be/rPx2OdtSOYI”rel = “ nofollow norefrer”> https://youtu.be/rpx2odtsoyi

enter image description here

    <StackPanel>
<Grid>
<Grid.Resources>
<Style TargetType="{x:Type Grid}">
<Setter Property="Margin" Value="-5 0"/>
</Style>
</Grid.Resources>


<Grid>
<Grid.Resources>
<Style TargetType="{x:Type Button}">
<Setter Property="Margin" Value="10 0"/>
</Style>
</Grid.Resources>


<Grid.ColumnDefinitions>
<ColumnDefinition Width="*" />
<ColumnDefinition Width="*" />
<ColumnDefinition Width="*" />
</Grid.ColumnDefinitions>


<Button Grid.Column="0" Content="Btn 1" />
<Button Grid.Column="1" Content="Btn 2" />
<Button Grid.Column="2" Content="Btn 3" />
</Grid>


</Grid>


<TextBlock FontWeight="Bold" Margin="0 10">
Test
</TextBlock>
</StackPanel>

编辑:

若要为任何控件提供页边距,可以像下面这样用边框包装该控件

<!--...-->
<Border Padding="10">
<AnyControl>
<!--...-->

我有类似的问题,最近在两列网格,我需要一个元素的右栏边距只。两列中的所有元素都属于 TextBlock 类型。

<Grid.Resources>
<Style TargetType="{x:Type TextBlock}" BasedOn="{StaticResource OurLabelStyle}">
<Style.Triggers>
<Trigger Property="Grid.Column" Value="1">
<Setter Property="Margin" Value="20,0" />
</Trigger>
</Style.Triggers>
</Style>
</Grid.Resources>