154

是否可以轻松地为 WPF 网格中的行或列指定边距和/或填充?

我当然可以添加额外的列来分隔内容,但这似乎是填充/边距的工作(它将提供简单的XAML)。有人从标准网格派生来添加此功能吗?

4

15 回答 15

97

RowDefinitionColumnDefinition属于 ,ContentElement严格Margin来说是一个FrameworkElement属性。因此,对于您的问题,“这很容易吗”,答案是肯定的。不,我还没有看到任何展示这种功能的布局面板。

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

于 2009-08-24T04:23:59.347 回答
82

使用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>


来源:

于 2012-12-14T06:16:23.267 回答
21

你可以使用这样的东西:

<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>
于 2011-04-14T09:10:54.050 回答
8

以为我会添加自己的解决方案,因为还没有人提到这一点。您可以使用样式声明来定位网格中包含的控件,而不是设计基于 Grid 的 UserControl。负责为所有元素添加填充/边距,而不必为每个元素定义,这既麻烦又费力。例如,如果您的 Grid 只包含 TextBlocks,您可以这样做:

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

这就像“单元格填充”的等价物。

于 2016-02-16T00:33:14.100 回答
5

编辑:

要为任何控件留出边距,您可以像这样用边框包裹控件

<!--...-->
    <Border Padding="10">
            <AnyControl>
<!--...-->
于 2019-01-18T13:06:39.783 回答
4

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

于 2009-08-28T15:50:18.767 回答
4

在 uwp (Windows10FallCreatorsUpdate 版本及以上)

<Grid RowSpacing="3" ColumnSpacing="3">
于 2017-12-05T20:10:30.093 回答
3

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

<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>

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

于 2015-02-14T16:21:00.497 回答
2

我现在用我的一个网格做到了。

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

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

来自网络,像 bootstrap 这样的框架将使用负边距来拉回行/列。

它可能有点冗长(尽管还不错),但它确实有效,并且元素的间距和大小均匀。

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

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

更新: 用户的一些评论说它不起作用,这里有一个快速视频演示:https ://youtu.be/rPx2OdtSOYI

在此处输入图像描述

    <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>
于 2018-08-16T18:20:17.643 回答
2

我最近在两列网格中遇到了类似的问题,我只需要右列元素的边距。两列中的所有元素都是 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>
于 2019-02-18T11:45:27.337 回答
1

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

您可能还认为您受到容器大小的限制,并且网格将变得与包含元素或其指定的宽度和高度一样大。您可以简单地使用没有设置宽度或高度的列和行。这样,他们默认均匀地分解网格内的总空间。那么它只是在你的网格中垂直和水平地居中你的元素。

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

于 2011-03-23T17:36:14.787 回答
0

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

这样(如果您在单击按钮时显示或隐藏控件),则无需在可能与之交互的每个控件上添加边距。

将其视为将控件组隔离为单元,然后将样式应用于这些单元。

于 2015-08-04T18:42:08.297 回答
0

如前所述,创建一个 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>
于 2017-02-21T20:30:47.587 回答
-8

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

您也可以简单地插入具有固定大小的空白列/行。非常简单,您可以轻松更改它。

于 2017-02-05T01:56:19.667 回答