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

发布于 2024-08-02 11:15:35 字数 128 浏览 6 评论 0原文

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

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

Is it easily possible to specify a margin and/or padding for rows or columns in a WPF Grid?

I could of course add extra columns to space things out, but this seems like a job for padding/margins (it will give much simplier XAML). Has someone derived from the standard Grid to add this functionality?

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(15

小鸟爱天空丶 2024-08-09 11:15:35

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

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

RowDefinition and ColumnDefinition are of type ContentElement, and Margin is strictly a FrameworkElement property. So to your question, "is it easily possible" the answer is a most definite no. And no, I have not seen any layout panels that demonstrate this kind of functionality.

You can add extra rows or columns as you suggested. But you can also set margins on a Grid element itself, or anything that would go inside a Grid, so that's your best workaround for now.

作妖 2024-08-09 11:15:35

在单元格控件外部使用 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>

来源:

Use a Border control outside the cell control and define the padding for that:

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

Source:

浅浅 2024-08-09 11:15:35

你可以使用这样的东西:

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

You could use something like this:

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

Or if you don't need the 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>
愚人国度 2024-08-09 11:15:35

我想我会添加自己的解决方案,因为还没有人提到这一点。您可以使用样式声明来定位网格中包含的控件,而不是基于网格设计用户控件。负责向所有元素添加填充/边距,而无需为每个元素进行定义,这既麻烦又费力。例如,如果您的网格只包含文本块,则可以执行以下操作:

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

这相当于“单元格填充” ”。

Thought I'd add my own solution because nobody yet mentioned this. Instead of designing a UserControl based on Grid, you can target controls contained in grid with a style declaration. Takes care of adding padding/margin to all elements without having to define for each, which is cumbersome and labor-intensive.For instance, if your Grid contains nothing but TextBlocks, you can do this:

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

Which is like the equivalent of "cell padding".

趴在窗边数星星i 2024-08-09 11:15:35

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

来自网络的框架(例如 bootstrap)将使用负边距来拉回行/列。

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

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

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

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

“在此处输入图像描述"

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

I am surprised I did not see this solution posted yet.

Coming from the web, frameworks like bootstrap will use a negative margin to pull back rows / columns.

It might be a little verbose (albeit not that bad), it does work and the elements are evenly spaced and sized.

In the example below I use a StackPanel root to demonstrate how the 3 buttons are evenly spaced using margins. You could use other elements, just change the inner x:Type from button to your element.

The idea is simple, use a grid on the outside to pull the margins of elements out of their bounds by half the amount of the inner grid (using negative margins), use the inner grid to evenly space the elements with the amount you want.

Update:
Some comment from a user said it doesn't work, here's a quick video demonstrating: 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>
谎言月老 2024-08-09 11:15:35

编辑:

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

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

Edited:

To give margin to any control you could wrap the control with border like this

<!--...-->
    <Border Padding="10">
            <AnyControl>
<!--...-->
哑剧 2024-08-09 11:15:35

我最近在两列网格中遇到了类似的问题,我只需要右列元素的边距。两列中的所有元素都是 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>

I had similar problem recently in two column grid, I needed a margin on elements in right column only. All elements in both columns were of type 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>
痴者 2024-08-09 11:15:35

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

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

I did it right now with one of my grids.

  • First apply the same margin to every element inside the grid. You can do this mannualy, using styles, or whatever you like. Lets say you want an horizontal spacing of 6px and a vertical spacing of 2px. Then you add margins of "3px 1px" to every child of the grid.
  • Then remove the margins created around the grid (if you want to align the borders of the controls inside the grid to the same position of the grid). Do this setting a margin of "-3px -1px" to the grid. That way, other controls outside the grid will be aligned with the outtermost controls inside the grid.
瑕疵 2024-08-09 11:15:35

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

<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...我个人最喜欢这种方法的好处。

I ran into this problem while developing some software recently and it occured to me to ask WHY? Why have they done this...the answer was right there in front of me. A row of data is an object, so if we maintain object orientation, then the design for a particular row should be seperated (suppose you need to re-use the row display later on in the future). So I started using databound stack panels and custom controls for most data displays. Lists have made the occasional appearance but mostly the grid has been used only for primary page organization (Header, Menu Area, Content Area, Other Areas). Your custom objects can easily manage any spacing requirements for each row within the stack panel or grid (a single grid cell can contain the entire row object. This also has the added benefit of reacting properly to changes in orientation, expand/collapses, etc.

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

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

or

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

Your Custom controls will also inherit the DataContext if your using data binding...my personal favorite benefit of this approach.

书间行客 2024-08-09 11:15:35

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

You could write your own GridWithMargin class, inherited from Grid, and override the ArrangeOverride method to apply the margins

不语却知心 2024-08-09 11:15:35

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

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

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

One possibility would be to add fixed width rows and columns to act as the padding / margin you are looking for.

You might also consider that you are constrained by the size of your container, and that a grid will become as large as the containing element or its specified width and height. You could simply use columns and rows with no width or height set. That way they default to evenly breaking up the total space within the grid. Then it would just be a mater of centering your elements vertically and horizontally within you grid.

Another method might be to wrap all grid elements in a fixed with single row & column grid that has a fixed size and margin. That your grid contains fixed width / height boxes which contain your actual elements.

┾廆蒐ゝ 2024-08-09 11:15:35

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

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

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

Though you can't add margin or padding to a Grid, you could use something like a Frame (or similar container), that you can apply it to.

That way (if you show or hide the control on a button click say), you won't need to add margin on every control that may interact with it.

Think of it as isolating the groups of controls into units, then applying style to those units.

蘸点软妹酱 2024-08-09 11:15:35

在uwp中(Windows10FallCreatorsUpdate版本及以上)

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

in uwp (Windows10FallCreatorsUpdate version and above)

<Grid RowSpacing="3" ColumnSpacing="3">
救赎№ 2024-08-09 11:15:35

如前所述,创建一个 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>

As was stated before create a GridWithMargins class.
Here is my working code example

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

Usage:

<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>
梦途 2024-08-09 11:15:35

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

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

Sometimes the simple method is the best. Just pad your strings with spaces. If it is only a few textboxes etc this is by far the simplest method.

You can also simply insert blank columns/rows with a fixed size. Extremely simple and you can easily change it.

~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文