StackPanel의 자식 요소를 어떻게 배치합니까?


187

StackPanel이 주어지면 :

<StackPanel>
  <TextBox Height="30">Apple</TextBox>
  <TextBox Height="80">Banana</TextBox>
  <TextBox Height="120">Cherry</TextBox>
</StackPanel>

자식 요소 자체의 크기가 다르더라도 자식 요소의 간격을 동일하게 유지하는 가장 좋은 방법은 무엇입니까? 개별 어린이 각각에 속성을 설정하지 않고 수행 할 수 있습니까?


실제로 개별 항목에 패딩을 추가하는 것이 가장 좋습니다.
ZAR

답변:


278

컨테이너 내의 범위에 적용된 여백 또는 패딩을 사용하십시오.

<StackPanel>
    <StackPanel.Resources>
        <Style TargetType="{x:Type TextBox}">
            <Setter Property="Margin" Value="0,10,0,0"/>
        </Style>
    </StackPanel.Resources> 
    <TextBox Text="Apple"/>
    <TextBox Text="Banana"/>
    <TextBox Text="Cherry"/>
</StackPanel>

편집 : 두 컨테이너 사이의 여백을 다시 사용하려는 경우 여백 값을 외부 범위의 리소스로 변환 할 수 있습니다.

<Window.Resources>
    <Thickness x:Key="tbMargin">0,10,0,0</Thickness>
</Window.Resources>

그런 다음 내부 범위에서이 값을 참조하십시오.

<StackPanel.Resources>
    <Style TargetType="{x:Type TextBox}">
        <Setter Property="Margin" Value="{StaticResource tbMargin}"/>
    </Style>
</StackPanel.Resources>

5
스코프 스타일은 멋진 방법입니다. 팁을 주셔서 감사합니다!
Ana Betts

2
전체 프로젝트에 사용하려면 어떻게합니까?
grv_9098

10
누군가 명시 적으로 유형 (예 : TextBox)을 정의 할 때 왜 이것이 작동하는지 설명 할 수 있습니까? 모든 자식이 간격을 갖도록 FrameworkElement를 사용하여 시도하면 아무런 효과가 없습니다.
잭 Ukleja

4
에 대한 스타일을 이미 정의한 경우 제대로 작동하지 않습니다 Button.
Mark Ingram

1
당신은이 작업을 수행하려면 보조 노트로서, Label당신은 사용할 필요가 Padding대신Margin
안토니 니콜스

84

또 다른 좋은 접근법은 여기에서 볼 수 있습니다 : http://blogs.microsoft.co.il/blogs/eladkatz/archive/2011/05/29/what-is-the-easiest-way-to-set-spacing-between- 항목 -에 - stackpanel.aspx > - 링크가 고장 이 webarchive입니다 이 링크의.

첨부 된 비헤이비어를 만드는 방법을 보여 주므로 다음과 같은 구문이 작동합니다.

<StackPanel local:MarginSetter.Margin="5">
   <TextBox Text="hello" />
   <Button Content="hello" />
   <Button Content="hello" />
</StackPanel>

이것은 여백이 같은 유형이 아니더라도 여백을 패널의 여러 자식으로 설정하는 가장 쉽고 빠른 방법입니다. (즉, 버튼, 텍스트 상자, 콤보 상자 등)


5
이것은 이것에 대해 꽤 흥미로운 방법입니다. 정확하게 물건을 배치하는 방법에 대한 많은 가정을하고 첫 번째 / 마지막 항목의 여백을 자동으로 조정할 수있는 기회를 제공합니다.
Armentage

2
다양성 : +1 또한 블로그 게시물을 개선하기 위해 if (fe.ReadLocalValue(FrameworkElement.MarginProperty) == DependencyProperty.UnsetValue)실제로 자식의 여백을 설정하기 전에 추가하여 일부 요소의 여백을 수동으로 지정할 수 있습니다.
Xerillio

하위 컬렉션이 변경되는 컬렉션에 바인딩 된 ItemsControl과 같이 동적으로 추가 / 제거되는 경우에는 작동하지 않습니다.
Drew Noakes

1
작동하지 않는 경우 : 프로젝트를 빌드하십시오. 그렇지 않으면 페이지가 렌더링되지 않습니다.
Battle

2
링크가 끊어졌습니다!
데이브

13

Elad Katz의 답변이 향상되었습니다 .

  • LastItemMargin 속성을 MarginSetter에 추가하여 마지막 항목을 특별히 처리하십시오.
  • 세로 및 가로 목록에서 항목 사이에 간격을 추가하고 목록 끝에서 후행 여백을 제거하는 세로 및 가로 속성으로 간격 첨부 속성 추가

gist 소스 코드 .

예:

<StackPanel Orientation="Horizontal" foo:Spacing.Horizontal="5">
  <Button>Button 1</Button>
  <Button>Button 2</Button>
</StackPanel>

<StackPanel Orientation="Vertical" foo:Spacing.Vertical="5">
  <Button>Button 1</Button>
  <Button>Button 2</Button>
</StackPanel>

<!-- Same as vertical example above -->
<StackPanel Orientation="Vertical" foo:MarginSetter.Margin="0 0 0 5" foo:MarginSetter.LastItemMargin="0">
  <Button>Button 1</Button>
  <Button>Button 2</Button>
</StackPanel>

Elad의 답변과 마찬가지로 하위 항목이 ItemsControl변경되는 컬렉션에 바인딩되는 것과 같이 동적으로 추가 / 제거되는 경우 작동하지 않습니다 . 부모의 Load이벤트가 시작 되는 순간부터 항목이 정적이라고 가정합니다 .
Drew Noakes

또한, 당신의 요지는 404를 제공합니다.
Drew Noakes

요점에 대한 링크가 업데이트되었습니다.
angularsen

9

당신이 정말로하고 싶은 것은 모든 자식 요소를 감싸는 것입니다. 이 경우 아이템 컨트롤을 사용해야하며 끔찍한 부착물에 의존해서는 안됩니다.

<ItemsControl>

    <!-- target the wrapper parent of the child with a style -->
    <ItemsControl.ItemContainerStyle>
        <Style TargetType="Control">
            <Setter Property="Margin" Value="0 0 5 0"></Setter>
        </Style>
    </ItemsControl.ItemContainerStyle>

    <!-- use a stack panel as the main container -->
    <ItemsControl.ItemsPanel>
        <ItemsPanelTemplate>
            <StackPanel Orientation="Horizontal"/>
        </ItemsPanelTemplate>
    </ItemsControl.ItemsPanel>

    <!-- put in your children -->
    <ItemsControl.Items>
        <Label>Auto Zoom Reset?</Label>
        <CheckBox x:Name="AutoResetZoom"/>
        <Button x:Name="ProceedButton" Click="ProceedButton_OnClick">Next</Button>
        <ComboBox SelectedItem="{Binding LogLevel }" ItemsSource="{Binding LogLevels}" />
    </ItemsControl.Items>
</ItemsControl>

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


유용한 팁이지만 Style TargetType과 함께 "FrameworkElement"로 더 잘 작동합니다 (그렇지 않으면 이미지에서는 작동하지 않음)
Puffin

1
나는이 아이디어를 좋아한다. 하나의 추가 사항 : StackPanel ( Margin="0 0 -5 0") 의 여백에서 간격의 양을 빼면 목록의 마지막 항목 다음의 간격도 카운터됩니다.
label17

이것의 문제점은 설정 한 스타일이 항목에 이미있을 수있는 다른 스타일보다 우선한다는 것입니다. 이것을 극복하기 위해 여기에
waxingsatirical

6

Sergey의 답변에 +1. 그리고 모든 StackPanel에 적용하려면 다음을 수행하십시오.

<Style TargetType="{x:Type StackPanel}">
    <Style.Resources>
        <Style TargetType="{x:Type TextBox}">
            <Setter Property="Margin" Value="{StaticResource tbMargin}"/>
        </Style>
    </Style.Resources>
</Style>

그러나 App.xaml (또는 Application.Resources에 병합 된 다른 사전)에서 이와 같은 스타일을 정의 하면 컨트롤의 기본 스타일을 재정의 할 있습니다. 스택 패널과 같은 대부분 보이지 않는 컨트롤의 경우 문제가되지 않지만 텍스트 상자 등의 경우이 문제가 발생 하여 운 좋게도 해결 방법이 있습니다.


<Style.Resources> 이것을 시도했을 때 coz에 대해 확신이 있으니 오류가 표시되었습니다.
grv_9098

미안하지만 기억이 안 나 나는 그것을 직접보아야 할 것이다. 너에게 다시 돌아갈 게.
Andre Luus

예, 작동합니다. StackPanel의 모든 TextBlocks에서 TextWeight = "Bold"를 설정하기 위해 동일하게 수행했습니다. 차이점은 StackPanel에서 스타일을 명시 적으로 설정했다는 것입니다.
Andre Luus

걱정 해 주셔서 감사하지만 의심의 여지가 있습니다. 스코프 스타일이라고합니다. <Style.Resources>가 아닌 <StackPanel.Resources>이 될 것입니다. 당신의 코드 조각을 붙여 넣을 수 있다면 더 좋을 것입니다 ...
grv_9098 10

3

Sergey의 제안에 따라 두께 객체 대신 전체 스타일 (여백을 포함한 다양한 속성 설정 기 포함)을 정의하고 재사용 할 수 있습니다.

<Style x:Key="MyStyle" TargetType="SomeItemType">
  <Setter Property="Margin" Value="0,5,0,5" />
  ...
</Style>

...

  <StackPanel>
    <StackPanel.Resources>
      <Style TargetType="SomeItemType" BasedOn="{StaticResource MyStyle}" />
    </StackPanel.Resources>
  ...
  </StackPanel>

여기서의 트릭은 암시 적 스타일에 스타일 상속을 사용하고 외부 (아마도 XAML 파일에서 병합 된) 리소스 사전의 스타일에서 상속하는 것입니다.

사이드 노트 :

처음에는 암시적인 스타일을 사용하여 컨트롤의 Style 속성을 외부 스타일 리소스 (예 : "MyStyle"키로 정의)로 설정하려고했습니다.

<StackPanel>
  <StackPanel.Resources>
    <Style TargetType="SomeItemType">
      <Setter Property="Style" Value={StaticResource MyStyle}" />
    </Style>
  </StackPanel.Resources>
</StackPanel>

https://connect.microsoft.com/VisualStudio/feedback/details/753211/xaml-editor-window-fails에 설명 된대로 CATASTROPHIC FAILURE 오류 (HRESULT : 0x8000FFFF (E_UNEXPECTED))로 인해 Visual Studio 2010이 즉시 종료되었습니다. -재해가 실패 할 때-스타일로 시도 할 때-설정된 스타일의 속성




2

내 접근 방식은 StackPanel을 상속합니다.

용법:

<Controls:ItemSpacer Grid.Row="2" Orientation="Horizontal" Height="30" CellPadding="15,0">
    <Label>Test 1</Label>
    <Label>Test 2</Label>
    <Label>Test 3</Label>
</Controls:ItemSpacer>

필요한 것은 다음과 같은 짧은 수업입니다.

using System.Windows;
using System.Windows.Controls;
using System;

namespace Controls
{
    public class ItemSpacer : StackPanel
    {
        public static DependencyProperty CellPaddingProperty = DependencyProperty.Register("CellPadding", typeof(Thickness), typeof(ItemSpacer), new FrameworkPropertyMetadata(default(Thickness), FrameworkPropertyMetadataOptions.BindsTwoWayByDefault, OnCellPaddingChanged));
        public Thickness CellPadding
        {
            get
            {
                return (Thickness)GetValue(CellPaddingProperty);
            }
            set
            {
                SetValue(CellPaddingProperty, value);
            }
        }
        private static void OnCellPaddingChanged(DependencyObject Object, DependencyPropertyChangedEventArgs e)
        {
            ((ItemSpacer)Object).SetPadding();
        }

        private void SetPadding()
        {
            foreach (UIElement Element in Children)
            {
                (Element as FrameworkElement).Margin = this.CellPadding;
            }
        }

        public ItemSpacer()
        {
            this.LayoutUpdated += PART_Host_LayoutUpdated;
        }

        private void PART_Host_LayoutUpdated(object sender, System.EventArgs e)
        {
            this.SetPadding();
        }
    }
}

0

때로는 항목 사이의 공간을 기본값보다 작게 만들기 위해 여백이 아닌 패딩을 설정해야 할 때가 있습니다.

당사 사이트를 사용함과 동시에 당사의 쿠키 정책개인정보 보호정책을 읽고 이해하였음을 인정하는 것으로 간주합니다.
Licensed under cc by-sa 3.0 with attribution required.