WPF : 열 / 행 여백 / 패딩이있는 그리드?


137

WPF Grid에서 행 또는 열에 대한 여백 및 / 또는 패딩을 쉽게 지정할 수 있습니까?

물론 공간을 넓히기 위해 여분의 열을 추가 할 수는 있지만 패딩 / 여백 작업처럼 보입니다 ( XAML이 훨씬 간단합니다). 이 기능을 추가하기 위해 표준 그리드에서 파생 된 사람이 있습니까?


4
하나의 유용한 예를 들어 당신은 여기 찾을 수 있습니다 codeproject.com/Articles/107468/WPF-Padded-Grid
peter70

2
킨다는 이것이 그리드의 기본 기능의 일부가 아니라고 당황했습니다.
uceumern

오늘날 10 년의 답변으로 입증 된 것처럼, 진실은 쉽게 가능하지 않으며, (셀을 사용할 때마다 추가 오류가 발생하기 쉬운 작업을 피하기 위해) 최선을 다하는 것이 그리드파생시키는 것입니다 (@ peter70에서 이전에 제안한대로) )를 사용하여 셀 하위의 여백 속성을 제어하는 ​​적절한 셀 패딩 종속성 속성을 추가하십시오. 이것은 긴 작업이 아니며 재사용 가능한 제어가 가능합니다. 측면 설명 ... 그리드는 실제로 잘못 설계된 컨트롤입니다.

답변:


10

GridWithMargin에서 상속받은 자신의 클래스를 작성 Grid하고 ArrangeOverride메소드를 재정 의하여 여백을 적용 할 수 있습니다


32
나는 사람들이 당신이 생각하고 설명하는 것만 큼 쉽지 않기 때문에 왜 사람들이 당신에게 엄지 손가락을 포기하는지 이해하지 못합니다. 30 분만 시도하면 답을 적용 할 수 없다는 것을 금방 알 수 있습니다. 또한 행과 열 스패닝에 대해 생각
에릭 Ouellet

89

RowDefinitionColumnDefinition유형입니다 ContentElement, 그리고 Margin엄격입니다 FrameworkElement속성입니다. 당신의 질문에 "쉽게 가능하다" 라는 대답은 가장 확실한 대답이 아닙니다. 그리고 아니요, 이런 종류의 기능을 보여주는 레이아웃 패널을 보지 못했습니다.

제안한대로 추가 행이나 열을 추가 할 수 있습니다. 그러나 Grid요소 자체 또는에 들어갈 항목 에 여백을 설정할 수도 Grid있으므로 지금은 가장 좋은 해결 방법입니다.


OP가 RowDefinition 또는 ColumnDefinition에서 여백을 설정하려고하지 않습니다. 그는 FrameworkElement에서 파생 된 표의 시각적 자식에 여백을 설정하려고합니다.
15ee8f99-57ff-4f92-890c-b56153

58

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


출처:


2
@RichardEverett Way Back Machine 확인 : 링크가 업데이트되었습니다.
CJBS

이 답변이 가장 좋습니다. 그것은 원래의 질문에 대한 해결책을 제공하며 간단합니다. 감사!
Tobias

이것은 쉽고 실용적입니다
aggsol

19

다음과 같은 것을 사용할 수 있습니다.

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

28
JayGee에게 감사합니다. 그러나이 솔루션은 표준 Grid 컨트롤이 아닌 DataGrid를위한 것입니다.
브래드 리치

패딩 공간을 클릭해도 더 이상 행이 선택되지 않습니다.
JOR

9

아무도 이것을 언급하지 않았기 때문에 내 솔루션을 추가 할 것이라고 생각했습니다. 그리드를 기반으로 UserControl을 디자인하는 대신 스타일 선언으로 그리드에 포함 된 컨트롤을 대상으로 지정할 수 있습니다. 번거롭고 노동 집약적 인 각 요소에 대해 정의하지 않고도 모든 요소에 패딩 / 여백을 추가하는 것을 처리합니다. 예를 들어, Grid에 TextBlocks 만 포함되어 있으면 다음과 같이 할 수 있습니다.

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

"셀 패딩"과 같습니다.


이 세류가 다운됩니까? 예를 들어 그리드 행에 스택 패널이있는 경우 스택 패널의 텍스트 블록 자식이이 속성을 상속합니까?
Maslow

그것이 바로 직계의 어린이를 지나칠 지 확실하지 않지만 간단한 테스트로 확인할 수 있습니다.
James M

2
@Maslow 대답은 절대적으로 '예'이지만, 당신의 말은 약간 오도됩니다. 더 "상속"의 없습니다 Margin속성이 일어나고, 그것은 모든 것을의 StyleA의가 ResourceDictionary자사의 모든 요소에 적용되는 TargetType모든 곳에서 전체 범위 내에서 그 사전의 소유자 요소는. 그래서 그것은 Style재산이 아니라 그 세류입니다.
Glenn Slayden

8

이것은 그리 어렵지 않습니다. 2009 년에 질문을 받았을 때 얼마나 어려웠는지 말할 수는 없었습니다.

이 솔루션을 사용할 때 그리드의 하위에 직접 여백을 직접 설정하면 해당 여백은 디자이너에는 나타나지만 런타임에는 나타나지 않습니다.

이 속성은 Grid, StackPanel, WrapPanel, UniformGrid 또는 기타 Panel의 자손에 적용 할 수 있습니다. 즉각적인 어린이에게 영향을 미칩니다. 아이들은 자신의 컨텐츠의 레이아웃을 관리하기를 원할 것으로 추정됩니다.

PanelExt.cs

public static class PanelExt
{
    public static Thickness? GetChildMargin(Panel obj)
    {
        return (Thickness?)obj.GetValue(ChildMarginProperty);
    }

    public static void SetChildMargin(Panel obj, Thickness? value)
    {
        obj.SetValue(ChildMarginProperty, value);
    }

    /// <summary>
    /// Apply a fixed margin to all direct children of the Panel, overriding all other margins.
    /// Panel descendants include Grid, StackPanel, WrapPanel, and UniformGrid
    /// </summary>
    public static readonly DependencyProperty ChildMarginProperty =
        DependencyProperty.RegisterAttached("ChildMargin", typeof(Thickness?), typeof(PanelExt),
            new PropertyMetadata(null, ChildMargin_PropertyChanged));

    private static void ChildMargin_PropertyChanged(DependencyObject d, DependencyPropertyChangedEventArgs e)
    {
        var target = d as Panel;

        target.Loaded += (s, e2) => ApplyChildMargin(target, (Thickness?)e.NewValue);

        ApplyChildMargin(target, (Thickness?)e.NewValue);
    }

    public static void ApplyChildMargin(Panel panel, Thickness? margin)
    {
        int count = VisualTreeHelper.GetChildrenCount(panel);

        object value = margin.HasValue ? margin.Value : DependencyProperty.UnsetValue;

        for (var i = 0; i < count; ++i)
        {
            var child = VisualTreeHelper.GetChild(panel, i) as FrameworkElement;

            if (child != null)
            {
                child.SetValue(FrameworkElement.MarginProperty, value);
            }
        }
    }
}

데모:

MainWindow.xaml

<Grid
    local:PanelExt.ChildMargin="2"
    x:Name="MainGrid"
    >
    <Grid.RowDefinitions>
        <RowDefinition />
        <RowDefinition />
        <RowDefinition Height="Auto" />
        <RowDefinition Height="Auto" />
    </Grid.RowDefinitions>
    <Grid.ColumnDefinitions>
        <ColumnDefinition />
        <ColumnDefinition />
    </Grid.ColumnDefinitions>
    <Rectangle Width="100" Height="40" Fill="Red" Grid.Row="0" Grid.Column="0" />
    <Rectangle Width="100" Height="40" Fill="Green" Grid.Row="1" Grid.Column="0" />
    <Rectangle Width="100" Height="40" Fill="Blue" Grid.Row="1" Grid.Column="1" />

    <Button Grid.Row="2" Grid.Column="0" Click="NoMarginClick">No Margin</Button>
    <Button Grid.Row="2" Grid.Column="1" Click="BigMarginClick">Big Margin</Button>
    <ComboBox Grid.Row="3" Grid.Column="0" Grid.ColumnSpan="2" />
</Grid>

MainWindow.xaml.cs

public partial class MainWindow : Window
{
    public MainWindow()
    {
        InitializeComponent();
    }

    private void NoMarginClick(object sender, RoutedEventArgs e)
    {
        //  In real life, if we wanted to change PanelExt.ChildMargin at runtime, we 
        //  would prefer to bind it to something, probably a dependency property of 
        //  the view. But this will do for a demonstration. 
        PanelExt.SetChildMargin(MainGrid, null);
    }
    private void BigMarginClick(object sender, RoutedEventArgs e)
    {
        PanelExt.SetChildMargin(MainGrid, new Thickness(20));
    }
}

여기에 이미지 설명을 입력하십시오

여기에 이미지 설명을 입력하십시오

여기에 이미지 설명을 입력하십시오


답이 다운 보트 인 이유를 알고 있습니까? OP의 문제에 대한 해결책으로 보인다
시스템

4
@ thesystem 누군가가 무언가에 대해 화가 났다고 생각합니다. 별거 아니야 그러나 내가 놓친 버그가있을 수 있습니다. 일어난다.
15ee8f99-57ff-4f92-890c-b56153

라이브 미리보기가 표시되기 전에 build또는 필요 run하기 때문에 dw가 있습니까? 좋고 간단한 것. 1 위로
Meow Cat 2012 년

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를 상속합니다.


여기서 시도한 ListView것은 GridView모드 에서 WPF 컨트롤 의 조잡한 버전 을 만드는 것이지만 모든“RowObjects”를 동일한 열 너비로 공유 할 수는 없습니다. 실제로는 더 이상 Grid와 관련이 없습니다.
Glenn Slayden


3

편집 :

컨트롤에 여백을 주려면 다음과 같이 테두리로 컨트롤을 감싸십시오.

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

OP 문제는 그리드 주위에 여백이 없지만 그리드 셀 주위에 여백이 있습니다 (또는 실제로 행과 열 주위에 묻는 것처럼 " 추가 열 / 행을 추가하는 것은 정확히 내가 주석 을 피하려고 시도한 것 "과 모순됩니다 ) .

2

나는 지금 내 그리드 중 하나를 사용하여 그것을했습니다.

  • 먼저 그리드 내부의 모든 요소에 동일한 여백을 적용하십시오. 스타일을 사용하거나 원하는 것을 사용하여이 mannualy을 수행 할 수 있습니다. 6px의 가로 간격과 2px의 세로 간격을 원한다고 가정 해 봅시다. 그런 다음 격자의 모든 자식에 "3px 1px"의 여백을 추가합니다.
  • 그런 다음 그리드 주위에 생성 된 여백을 제거합니다 (그리드 내부의 컨트롤 테두리를 그리드의 동일한 위치에 정렬하려는 경우). 격자에 여백을 "-3px -1px"로 설정하십시오. 이렇게하면 그리드 외부의 다른 컨트롤이 그리드 내부의 가장 바깥 쪽 컨트롤과 정렬됩니다.

그리드 내부의 모든 요소에 동일한 여백을 적용하는 것이 가장 쉬운 방법 인 것 같습니다.
Envil

1

하나의 가능성은 찾고있는 패딩 / 여백으로 작동하도록 고정 너비 행과 열을 추가하는 것입니다.

컨테이너의 크기에 의해 제약을받으며 격자가 포함하는 요소 나 지정된 너비와 높이만큼 커질 수 있습니다. 너비 나 높이가 설정되지 않은 열과 행을 간단히 사용할 수 있습니다. 이렇게하면 그리드 내의 전체 공간이 균등하게 분할됩니다. 그런 다음 그리드 내에서 요소를 세로 및 가로로 가운데에 맞추는 것이 중요합니다.

다른 방법은 모든 그리드 요소를 고정 된 크기와 여백을 가진 단일 행 및 열 그리드로 고정하는 것입니다. 그리드에는 실제 요소를 포함하는 고정 너비 / 높이 상자가 포함되어 있습니다.


1
고마워 아담, 그러나 여분의 열 / 행을 추가하는 것은 내가 피하려고했던 것입니다. 마크 업을 줄이려고하고 여백이나 패딩을 지정할 수 있으면 도움이됩니다.
브래드 리치

여분의 열과 행만 정의하면되고 마크 업을 추가하지 않아도됩니다. 예를 들어, 3 개의 열에 대해 열 사이에 N 너비를 추가하려는 경우 5 개의 열 정의가 있습니다. 첫 번째는 자동 너비이고 다음은 고정, 자동, 고정, 자동입니다. 그런 다음 열 1, 3 및 5 만 실제 컨텐츠 요소에 지정하십시오. 여분의 열 마크 업에 대한 요점을 알지만 수백 가지 요소가 없다면 나에게 사소한 것 같습니다. 그래도 당신의 전화. 또한 여백이 설정된 스택 패널의 스택 패널을 사용해 보셨습니까?
Adam Lenda

필자의 경우 "스플리터 / 여백"열을 추가하는 것이 훨씬 깨끗하고 쉬웠습니다. 감사!
jchristof

1

최근에 두 개의 열 그리드에서 비슷한 문제가 발생했습니다. 오른쪽 열의 요소에만 여백이 필요했습니다. 두 열의 모든 요소는 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>

0

격자에 여백이나 패딩을 추가 할 수는 없지만 적용 할 수있는 프레임 (또는 유사한 컨테이너)과 같은 것을 사용할 수 있습니다.

그런 식으로 (버튼 클릭 말에 컨트롤을 표시하거나 숨기면) 컨트롤과 상호 작용할 수있는 모든 컨트롤에 여백을 추가 할 필요가 없습니다.

컨트롤 그룹을 단위로 분리 한 다음 해당 단위에 스타일을 적용하는 것으로 생각하십시오.


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>

1
System.ArgumentException : '너비가 음수가 아니어야합니다.' actual.Width-= Math.Min (actual.Width, RowMargin.Left + RowMargin.Right); actual.Height-= Math.Min (실제 높이, RowMargin.Top + RowMargin.Bottom);
Jamie Mellway

Jamie의 수정으로 실행되지만 여전히 필요한 작업을 수행하지 않습니다. 행 높이와 열 너비를 자동으로 설정하면 다른 방식으로 잘못된 일을합니다.
15ee8f99-57ff-4f92-890c-b56153

0

이 솔루션이 아직 게시되지 않은 것에 놀랐습니다.

웹에서 시작하면 부트 스트랩과 같은 프레임 워크는 음수 여백을 사용하여 행 / 열을 뒤로 당깁니다.

그것은 조금 장황 할 수도 있지만 (나쁘지는 않지만) 작동하며 요소의 간격과 크기가 균등합니다.

아래 예에서는 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>

1
내 실수-암시 적 단추 스타일을 보지 못했습니다. 나는 마이너스 마진에 대해 약간 산만했습니다.
15ee8f99-57ff-4f92-890c-b56153

-6

때로는 간단한 방법이 가장 좋습니다. 문자열을 공백으로 채우십시오. 단지 몇 개의 텍스트 상자 등이라면 이것이 가장 간단한 방법입니다.

고정 된 크기의 빈 열 / 행을 간단히 삽입 할 수도 있습니다. 매우 간단하며 쉽게 변경할 수 있습니다.


아마도 좋은 방법이 아니기 때문일 것입니다. 공백을 사용하는 것이 "쉬운 방법"일 수 있지만 실제로는 해킹에 가깝습니다. 정확하지는 않습니다. 다른 스케일링을 사용하는 모니터에서는 다르게 그리고 신뢰할 수 없을 정도로 렌더링 할 수 있으며 생성하는 정확한 공간을 제어 할 수 없습니다. 빈 열 / 행을 삽입하면 그리드가 엉망이됩니다 ...
Mark
당사 사이트를 사용함과 동시에 당사의 쿠키 정책개인정보 보호정책을 읽고 이해하였음을 인정하는 것으로 간주합니다.
Licensed under cc by-sa 3.0 with attribution required.