Share via


Panel 개요

업데이트: 2007년 11월

Panel 요소는 크기 및 차원, 위치, 자식 콘텐츠 정렬 등과 같은 요소 렌더링을 제어하는 구성 요소입니다. WPF(Windows Presentation Foundation)는 사용자 지정 Panel 요소를 생성하는 기능뿐만 아니라 미리 정의된 많은 Panel 요소를 제공합니다.

이 항목에는 다음 단원이 포함되어 있습니다.

  • Panel 클래스

  • Panel 요소의 공용 멤버

  • 파생 Panel 요소

  • 사용자 인터페이스 패널

  • 중첩 Panel 요소

  • 사용자 지정 Panel 요소

  • 지역화/전역화 지원

  • 관련 항목

Panel 클래스

Panel은 WPF(Windows Presentation Foundation)에서 레이아웃 지원을 제공하는 모든 요소에 대한 기본 클래스입니다. 파생 Panel 요소는 XAML(Extensible Application Markup Language) 및 코드에서 UIElements를 배치하고 정렬하는 데 사용됩니다.

WPF에는 여러 가지 복잡한 레이아웃을 가능하게 하는 광범위한 파생 패널 구현 집합이 포함되어 있습니다. 이러한 파생 클래스는 대부분의 표준 UI(사용자 인터페이스) 시나리오를 가능하게 하는 속성 및 메서드를 노출합니다. 요구에 맞는 자식 정렬 동작을 찾을 수 없는 개발자는 ArrangeOverrideMeasureOverride 메서드를 재정의하여 새 레이아웃을 만들 수 있습니다. 사용자 지정 레이아웃 동작에 대한 자세한 내용은 사용자 지정 Panel 요소를 참조하십시오.

XAMLPad

XAMLPad는 실시간으로 태그를 구문 분석하고 창에 결과를 표시하여 XAML(Extensible Application Markup Language) 기반 사용자 인터페이스를 보다 쉽게 개발할 수 있는 도구입니다. 이 도구는 레이아웃을 실험해 볼 때 매우 유용합니다. 이 항목에 포함된 다양한 XAML(Extensible Application Markup Language) 샘플의 결과를 보기 위해 이 응용 프로그램을 열어 놓을 수 있습니다. 자세한 내용은 XAMLPad를 참조하십시오.

Panel의 공용 멤버

모든 Panel 요소는 Height, Width, HorizontalAlignment, VerticalAlignment, MarginLayoutTransform을 비롯하여 FrameworkElement로 정의되는 기본 크기 조정 및 배치 속성을 지원합니다. FrameworkElement로 정의되는 배치 속성에 대한 자세한 내용은 맞춤, 여백 및 안쪽 여백 개요를 참조하십시오.

Panel은 레이아웃을 이해하고 사용하는 데 있어 매우 중요한 추가 속성을 노출합니다. Background 속성은 Brush를 사용하여 파생 panel 요소의 경계 사이의 영역을 채우는 데 사용됩니다. ChildrenPanel을 구성하는 UIElements의 자식 컬렉션을 나타냅니다. InternalChildren은 데이터 바인딩을 통해 생성된 멤버와 함께 Children 컬렉션의 콘텐츠를 나타냅니다. 둘 모두 부모 Panel 내에 호스팅되는 자식 요소의 UIElementCollection으로 구성됩니다.

Panel은 파생 Panel에서 계층화 정렬을 수행하는 데 사용할 수 있는 ZIndex 속성을 노출합니다. ZIndex 값이 큰 패널의 Children 컬렉션은 ZIndex 값이 작은 해당 컬렉션보다 앞에 나타납니다. 이는 자식이 동일한 좌표 공간을 공유할 수 있도록 허용하는 CanvasGrid와 같은 패널에 특히 유용합니다.

PanelPanel의 기본 표시 동작을 재정의하는 데 사용할 수 있는 OnRender 메서드도 정의합니다.

연결된 속성

파생 panel 요소는 연결된 속성을 광범위하게 사용합니다. 연결된 속성은 기존의 CLR(공용 언어 런타임) 속성 “래퍼”가 없는 종속성 속성의 특수 형식입니다. 연결된 속성에는 아래의 몇 가지 예제에서 볼 수 있는 XAML(Extensible Application Markup Language)의 특수 구문이 있습니다.

연결된 속성의 용도 중 하나는 실질적으로 부모 요소가 정의한 속성의 고유 값을 자식 요소가 저장할 수 있도록 하는 것입니다. 이 기능이 있는 응용 프로그램에서는 자식 요소가 자신이 UI(사용자 인터페이스)에 표시될 방법을 부모에게 알리게 됩니다. 이는 응용 프로그램 레이아웃에 매우 유용합니다. 자세한 내용은 연결된 속성 개요를 참조하십시오.

파생 Panel 요소

많은 개체가 Panel에서 파생되지만 이러한 모든 개체를 루트 레이아웃 공급자로 사용할 수는 없습니다. 응용 프로그램 UI를 만들기 위해 Canvas, DockPanel, Grid, StackPanel, VirtualizingStackPanelWrapPanel이라는 6개의 정의된 panel 클래스가 특별히 디자인되었습니다.

각 panel 요소는 다음 표와 같은 고유한 특수 기능을 캡슐화합니다.

요소 이름

UI 패널 여부

설명

Canvas

Canvas 영역에 상대적인 좌표를 사용하여 자식 요소를 명시적으로 배치할 수 있는 영역을 정의합니다.

DockPanel

자식 요소를 서로에 상대적으로 가로나 세로로 정렬할 수 있는 영역을 정의합니다.

Grid

열과 행으로 구성되는 유연한 표 영역을 정의합니다. Grid의 자식 요소는 Margin 속성을 사용하여 정확한 위치를 지정할 수 있습니다.

StackPanel

가로 또는 세로 방향으로 지정할 수 있는 한 줄에 자식 요소를 정렬합니다.

TabPanel

아니요

TabControl에 있는 탭 단추의 레이아웃을 처리합니다.

ToolBarOverflowPanel

아니요

ToolBar 컨트롤 내의 콘텐츠를 정렬합니다.

UniformGrid

아니요

UniformGrid는 셀 크기가 모두 동일한 표에 자식을 정렬하는 데 사용됩니다.

VirtualizingPanel

아니요

해당 자식 컬렉션을 "가상화"할 수 있는 패널에 대한 기본 클래스를 제공합니다.

VirtualizingStackPanel

가로 또는 세로 방향으로 지정된 한 줄에 콘텐츠를 정렬하고 가상화합니다.

WrapPanel

WrapPanel은 자식 요소를 왼쪽에서 오른쪽으로 순차적으로 배치하고, 포함하는 상자의 가장자리에서 내용을 다음 줄로 바꿉니다. 이후에는 Orientation 속성 값에 따라 순서가 위쪽에서 아래쪽으로 또는 오른쪽에서 왼쪽으로 순차적으로 지정됩니다.

사용자 인터페이스 패널

WPF에서는 UI 시나리오를 지원하기 위해 최적화된 6개의 panel 클래스인 Canvas, DockPanel, Grid, StackPanel, VirtualizingStackPanelWrapPanel을 사용할 수 있습니다. 이러한 panel 요소는 사용이 용이하고 융통성이 있으며 대부분의 응용 프로그램에 대해 충분히 확장 가능합니다.

각 파생 Panel 요소는 크기 조정 제약 조건을 서로 다르게 처리합니다. Panel이 가로 또는 세로 방향에서 제약 조건을 처리하는 방법을 이해하면 레이아웃을 예측하는 데 더욱 도움이 됩니다.

패널 이름

x 차원

y 차원

Canvas

콘텐츠의 제약을 받음

콘텐츠의 제약을 받음

DockPanel

제약을 받음

제약을 받음

StackPanel(세로 방향)

제약을 받음

콘텐츠의 제약을 받음

StackPanel(가로 방향)

콘텐츠의 제약을 받음

제약을 받음

Grid

제약을 받음

제약을 받음(예외: Auto가 행 및 열에 적용되는 경우)

WrapPanel

콘텐츠의 제약을 받음

콘텐츠의 제약을 받음

이러한 각 요소에 대한 자세한 내용 및 사용 예제는 아래를 참조하십시오.

캔버스

Canvas 요소를 사용하면 절대 x 좌표 및 y 좌표에 따라 콘텐츠의 위치를 지정할 수 있습니다. 요소를 고유 위치에 그릴 수 있지만 여러 요소가 동일한 좌표를 사용하는 경우에는 해당 요소가 태그에 나타나는 순서대로 요소가 그려집니다.

Canvas는 모든 Panel 중 가장 유연한 레이아웃 지원을 제공합니다. Height 및 Width 속성은 캔버스의 영역을 정의하는 데 사용되며 내부 요소에는 부모 Canvas의 영역에 상대적으로 절대 좌표가 할당됩니다. 4개의 연결된 속성 Left, Top, RightBottom을 사용하면 Canvas 내에서의 개체 배치를 보다 자세히 제어할 수 있으므로 개발자가 화면에서 요소를 정확하게 배치 및 정렬할 수 있습니다.

캔버스 내의 ClipToBounds

Canvas는 정의된 자체 HeightWidth를 벗어나는 좌표를 비롯하여 화면의 모든 위치에 자식 요소를 배치할 수 있습니다. 또한 Canvas는 자식 크기에 의해 영향을 받지 않습니다. 따라서 자식 요소는 부모 Canvas의 경계 사각형을 벗어나는 다른 요소를 그릴 수 있습니다. 부모 Canvas의 범위를 벗어나는 자식을 그릴 수 있는 것이 Canvas의 기본 동작입니다. 이러한 동작이 필요 없는 경우에는 ClipToBounds 속성을 true로 설정합니다. 이렇게 하면 Canvas가 자체 크기로 클리핑됩니다. Canvas는 해당 범위를 벗어나는 자식을 그릴 수 있도록 허용하는 유일한 레이아웃 요소입니다.

이러한 동작에 대한 그림을 보려면 너비 속성 비교 샘플을 참조하십시오.

캔버스 정의 및 사용

XAML(Extensible Application Markup Language) 또는 코드를 사용하면 Canvas를 간단하게 인스턴스화할 수 있습니다. 다음 예제에서는 Canvas를 사용하여 콘텐츠의 절대 위치를 지정하는 방법을 보여 줍니다. 이 코드에서는 세 개의 100픽셀 사각형을 생성합니다. 첫 번째 사각형은 빨간색이며 왼쪽 위(x, y) 위치가 (0, 0)으로 지정됩니다. 두 번째 사각형은 녹색이며 첫 번째 사각형의 바로 아래 오른쪽인 (100, 100)으로 왼쪽 위 위치가 지정됩니다. 세 번째 사각형은 파란색이며 왼쪽 위 위치는 (50, 50)입니다. 따라서 세 번째 사각형은 첫 번째 사각형의 오른쪽 아래 1/4과 두 번째의 왼쪽 위 1/4을 덮습니다. 세 번째 사각형은 마지막에 배치되므로 다른 두 사각형의 위에 표시됩니다. 즉, 겹친 부분의 색은 세 번째 상자의 색입니다.

WindowTitle = "Canvas Sample"
'Create a Canvas as the root Panel
Dim myParentCanvas As New Canvas()
myParentCanvas.Width = 400
myParentCanvas.Height = 400

' Define child Canvas elements
Dim myCanvas1 As New Canvas()
myCanvas1.Background = Brushes.Red
myCanvas1.Height = 100
myCanvas1.Width = 100
Canvas.SetTop(myCanvas1, 0)
Canvas.SetLeft(myCanvas1, 0)

Dim myCanvas2 As New Canvas()
myCanvas2.Background = Brushes.Green
myCanvas2.Height = 100
myCanvas2.Width = 100
Canvas.SetTop(myCanvas2, 100)
Canvas.SetLeft(myCanvas2, 100)

Dim myCanvas3 As New Canvas()
myCanvas3.Background = Brushes.Blue
myCanvas3.Height = 100
myCanvas3.Width = 100
Canvas.SetTop(myCanvas3, 50)
Canvas.SetLeft(myCanvas3, 50)

' Add child elements to the Canvas' Children collection
myParentCanvas.Children.Add(myCanvas1)
myParentCanvas.Children.Add(myCanvas2)
myParentCanvas.Children.Add(myCanvas3)

' Add the parent Canvas as the Content of the Window Object
Me.Content = myParentCanvas
// Create the application's main window
mainWindow = new Window ();
mainWindow.Title = "Canvas Sample";

// Create the Canvas
myParentCanvas = new Canvas();
myParentCanvas.Width = 400;
myParentCanvas.Height = 400;

// Define child Canvas elements
myCanvas1 = new Canvas();
myCanvas1.Background = Brushes.Red;
myCanvas1.Height = 100;
myCanvas1.Width = 100;
Canvas.SetTop(myCanvas1, 0);
Canvas.SetLeft(myCanvas1, 0);

myCanvas2 = new Canvas();
myCanvas2.Background = Brushes.Green;
myCanvas2.Height = 100;
myCanvas2.Width = 100;
Canvas.SetTop(myCanvas2, 100);
Canvas.SetLeft(myCanvas2, 100);

myCanvas3 = new Canvas();
myCanvas3.Background = Brushes.Blue;
myCanvas3.Height = 100;
myCanvas3.Width = 100;
Canvas.SetTop(myCanvas3, 50);
Canvas.SetLeft(myCanvas3, 50);

// Add child elements to the Canvas' Children collection
myParentCanvas.Children.Add(myCanvas1);
myParentCanvas.Children.Add(myCanvas2);
myParentCanvas.Children.Add(myCanvas3);

// Add the parent Canvas as the Content of the Window Object
mainWindow.Content = myParentCanvas;
mainWindow.Show ();

<Page WindowTitle="Canvas Sample" xmlns="https://schemas.microsoft.com/winfx/2006/xaml/presentation">
  <Canvas Height="400" Width="400">
    <Canvas Height="100" Width="100" Top="0" Left="0" Background="Red"/>
    <Canvas Height="100" Width="100" Top="100" Left="100" Background="Green"/>
    <Canvas Height="100" Width="100" Top="50" Left="50" Background="Blue"/>
  </Canvas>
</Page>

컴파일된 응용 프로그램은 다음과 같은 새 UI를 생성합니다.

일반적인 Canvas 요소

DockPanel

DockPanel 요소는 연결된 Dock 속성을 사용하여 컨테이너의 가장자리를 따라 콘텐츠의 위치를 지정합니다. Dock을 Top 또는 Bottom으로 설정하면 자식 요소가 서로의 위 또는 아래에 배치됩니다. Dock을 Left 또는 Right로 설정하면 자식 요소가 서로의 왼쪽 또는 오른쪽에 배치됩니다. LastChildFill 속성은 DockPanel의 자식으로 추가되는 마지막 요소의 위치를 결정합니다.

DockPanel을 사용하여 단추 집합과 같이 서로 관련된 컨트롤 그룹을 배치할 수 있습니다. 이를 사용하여 Microsoft Outlook의 UI와 유사한 "창이 있는" UI를 만들 수도 있습니다.

콘텐츠에 맞게 크기 조정

해당 HeightWidth 속성을 지정하지 않으면 DockPanel의 크기가 해당 콘텐츠에 맞게 조정됩니다. 크기는 해당 자식 요소의 크기에 맞게 늘이거나 줄일 수 있습니다. 그러나 이러한 속성을 지정하며 다음으로 지정하는 자식 요소를 위한 공간이 더 이상 없는 경우에는 DockPanel이 해당 자식 요소 또는 후속 자식 요소를 표시하지 않으며 후속 자식 요소를 측정하지 않습니다.

LastChildFill

기본적으로 DockPanel 요소의 마지막 자식이 할당되지 않은 나머지 공간을 "채웁니다". 이러한 동작이 필요 없는 경우에는 LastChildFill 속성을 false로 설정합니다.

DockPanel 정의 및 사용

다음 예제에서는 DockPanel을 사용하여 공간을 분할하는 방법을 보여 줍니다. 5개의 Border 요소가 부모 DockPanel의 자식으로 추가됩니다. 각 요소는 DockPanel의 서로 다른 위치 지정 속성을 사용하여 공간을 분할합니다. 마지막 요소가 할당되지 않은 나머지 공간을 "채웁니다".

WindowTitle = "DockPanel Sample"
'Create a DockPanel as the root Panel
Dim myDockPanel As New DockPanel()
myDockPanel.LastChildFill = True

' Define the child content
Dim myBorder1 As New Border()
myBorder1.Height = 25
myBorder1.Background = Brushes.SkyBlue
myBorder1.BorderBrush = Brushes.Black
myBorder1.BorderThickness = New Thickness(1)
DockPanel.SetDock(myBorder1, Dock.Top)
Dim myTextBlock1 As New TextBlock()
myTextBlock1.Foreground = Brushes.Black
myTextBlock1.Text = "Dock = Top"
myBorder1.Child = myTextBlock1

Dim myBorder2 As New Border()
myBorder2.Height = 25
myBorder2.Background = Brushes.SkyBlue
myBorder2.BorderBrush = Brushes.Black
myBorder2.BorderThickness = New Thickness(1)
DockPanel.SetDock(myBorder2, Dock.Top)
Dim myTextBlock2 As New TextBlock()
myTextBlock2.Foreground = Brushes.Black
myTextBlock2.Text = "Dock = Top"
myBorder2.Child = myTextBlock2

Dim myBorder3 As New Border()
myBorder3.Height = 25
myBorder3.Background = Brushes.LemonChiffon
myBorder3.BorderBrush = Brushes.Black
myBorder3.BorderThickness = New Thickness(1)
DockPanel.SetDock(myBorder3, Dock.Bottom)
Dim myTextBlock3 As New TextBlock()
myTextBlock3.Foreground = Brushes.Black
myTextBlock3.Text = "Dock = Bottom"
myBorder3.Child = myTextBlock3

Dim myBorder4 As New Border()
myBorder4.Width = 200
myBorder4.Background = Brushes.PaleGreen
myBorder4.BorderBrush = Brushes.Black
myBorder4.BorderThickness = New Thickness(1)
DockPanel.SetDock(myBorder4, Dock.Left)
Dim myTextBlock4 As New TextBlock()
myTextBlock4.Foreground = Brushes.Black
myTextBlock4.Text = "Dock = Left"
myBorder4.Child = myTextBlock4

Dim myBorder5 As New Border()
myBorder5.Background = Brushes.White
myBorder5.BorderBrush = Brushes.Black
myBorder5.BorderThickness = New Thickness(1)
Dim myTextBlock5 As New TextBlock()
myTextBlock5.Foreground = Brushes.Black
myTextBlock5.Text = "This content will Fill the remaining space"
myBorder5.Child = myTextBlock5

' Add child elements to the DockPanel Children collection
myDockPanel.Children.Add(myBorder1)
myDockPanel.Children.Add(myBorder2)
myDockPanel.Children.Add(myBorder3)
myDockPanel.Children.Add(myBorder4)
myDockPanel.Children.Add(myBorder5)
Me.Content = myDockPanel
// Create the application's main window
mainWindow = new Window ();
mainWindow.Title = "DockPanel Sample";

// Create the DockPanel
DockPanel myDockPanel = new DockPanel();
myDockPanel.LastChildFill = true;

// Define the child content
Border myBorder1 = new Border();
myBorder1.Height = 25;
myBorder1.Background = Brushes.SkyBlue;
myBorder1.BorderBrush = Brushes.Black;
myBorder1.BorderThickness = new Thickness(1);
DockPanel.SetDock(myBorder1, Dock.Top);
TextBlock myTextBlock1 = new TextBlock();
myTextBlock1.Foreground = Brushes.Black;
myTextBlock1.Text = "Dock = Top";
myBorder1.Child = myTextBlock1;

Border myBorder2 = new Border();
myBorder2.Height = 25;
myBorder2.Background = Brushes.SkyBlue;
myBorder2.BorderBrush = Brushes.Black;
myBorder2.BorderThickness = new Thickness(1);
DockPanel.SetDock(myBorder2, Dock.Top);
TextBlock myTextBlock2 = new TextBlock();
myTextBlock2.Foreground = Brushes.Black;
myTextBlock2.Text = "Dock = Top";
myBorder2.Child = myTextBlock2;

Border myBorder3 = new Border();
myBorder3.Height = 25;
myBorder3.Background = Brushes.LemonChiffon;
myBorder3.BorderBrush = Brushes.Black;
myBorder3.BorderThickness = new Thickness(1);
DockPanel.SetDock(myBorder3, Dock.Bottom);
TextBlock myTextBlock3 = new TextBlock();
myTextBlock3.Foreground = Brushes.Black;
myTextBlock3.Text = "Dock = Bottom";
myBorder3.Child = myTextBlock3;

Border myBorder4 = new Border();
myBorder4.Width = 200;
myBorder4.Background = Brushes.PaleGreen;
myBorder4.BorderBrush = Brushes.Black;
myBorder4.BorderThickness = new Thickness(1);
DockPanel.SetDock(myBorder4, Dock.Left);
TextBlock myTextBlock4 = new TextBlock();
myTextBlock4.Foreground = Brushes.Black;
myTextBlock4.Text = "Dock = Left";
myBorder4.Child = myTextBlock4;

Border myBorder5 = new Border();
myBorder5.Background = Brushes.White;
myBorder5.BorderBrush = Brushes.Black;
myBorder5.BorderThickness = new Thickness(1);
TextBlock myTextBlock5 = new TextBlock();
myTextBlock5.Foreground = Brushes.Black;
myTextBlock5.Text = "This content will Fill the remaining space";
myBorder5.Child = myTextBlock5;


// Add child elements to the DockPanel Children collection
myDockPanel.Children.Add(myBorder1);
myDockPanel.Children.Add(myBorder2);
myDockPanel.Children.Add(myBorder3);
myDockPanel.Children.Add(myBorder4);
myDockPanel.Children.Add(myBorder5);

// Add the parent Canvas as the Content of the Window Object
mainWindow.Content = myDockPanel;
mainWindow.Show ();

<Page xmlns="https://schemas.microsoft.com/winfx/2006/xaml/presentation" WindowTitle="DockPanel Sample">
  <DockPanel LastChildFill="True">
    <Border Height="25" Background="SkyBlue" BorderBrush="Black" BorderThickness="1" DockPanel.Dock="Top">
      <TextBlock Foreground="Black">Dock = "Top"</TextBlock>
    </Border>
    <Border Height="25" Background="SkyBlue" BorderBrush="Black" BorderThickness="1" DockPanel.Dock="Top">
      <TextBlock Foreground="Black">Dock = "Top"</TextBlock>
    </Border>
    <Border Height="25" Background="LemonChiffon" BorderBrush="Black" BorderThickness="1" DockPanel.Dock="Bottom">
      <TextBlock Foreground="Black">Dock = "Bottom"</TextBlock>
    </Border>
    <Border Width="200" Background="PaleGreen" BorderBrush="Black" BorderThickness="1" DockPanel.Dock="Left">
      <TextBlock Foreground="Black">Dock = "Left"</TextBlock>
    </Border>
    <Border Background="White" BorderBrush="Black" BorderThickness="1">
      <TextBlock Foreground="Black">This content will "Fill" the remaining space</TextBlock>
    </Border>
  </DockPanel>
</Page>

컴파일된 응용 프로그램은 다음과 같은 새 UI를 생성합니다.

일반적인 DockPanel 시나리오

모눈

Grid 요소는 절대 위치 지정 컨트롤과 표 형식 데이터 컨트롤의 기능을 병합합니다. Grid를 사용하면 요소의 위치와 스타일을 쉽게 지정할 수 있습니다. 또한 Grid를 사용하면 유연한 행 및 열 그룹화를 정의할 수 있으며 여러 Grid 요소 간에 크기 조정 정보를 공유할 수 있는 메커니즘도 제공할 수 있습니다.

모눈과 표의 차이점

TableGrid는 공통된 기능을 공유하지만 각각 적합한 시나리오는 서로 다릅니다. Table은 유동 콘텐츠 내에서 사용되도록 설계된 것입니다. 유동 콘텐츠에 대한 자세한 내용은 유동 문서 개요를 참조하십시오. 모눈은 기본적으로는 유동 콘텐츠 외부 어디에서든 사용할 수 있으나 폼 내부에서 사용하기에 가장 적합합니다. FlowDocument 내부에서 Table은 페이지 매김, 열 흐름 변경 및 콘텐츠 선택과 같은 유동 콘텐츠 동작을 지원하지만 Grid는 지원하지 않습니다. 한편 GridGrid가 행 및 열 인덱스를 기반으로 요소를 추가하는 반면 Table은 그렇지 않다는 등의 여러 가지 이유에서 FlowDocument 외부에서 사용하기에 가장 적합합니다. Grid 요소를 사용하면 자식 콘텐츠를 계층화할 수 있으므로 단일 "셀" 내에 둘 이상의 요소가 존재할 수 있습니다. Table은 계층화를 지원하지 않습니다. Grid의 자식 요소는 해당 "셀" 경계 영역을 기준으로 절대 위치에 배치될 수 있습니다. Table은 이 기능을 지원하지 않습니다. 마지막으로 GridTable보다 간단합니다.

열 및 행의 크기 조정 동작

Grid 내에 정의된 열 및 행에 대해 Star 크기 조정을 활용하여 나머지 공간을 비례적으로 나눌 수 있습니다. Star를 행이나 열의 Height 또는 Width로 선택하면 사용 가능한 나머지 공간의 가중 크기가 해당 열이나 행에 할당됩니다. 이러한 동작은 열이나 행 내의 콘텐츠 크기에 따라 공간을 균등하게 나누는 Auto의 동작과 대조됩니다. 이 값은 * 또는 2*(XAML(Extensible Application Markup Language)을 사용할 경우)로 표현됩니다. 첫 번째 경우에는 행이나 열에 사용 가능한 공간의 1배가 할당되고 두 번째 경우에는 2배가 할당되는 식입니다. 별표를 사용한 크기 조정에 대한 자세한 내용은 별표를 사용한 크기 조정 샘플 샘플을 참조하십시오. 공간을 비례적으로 나누는 이 기술과 HorizontalAlignmentVerticalAlignment 값 Stretch를 함께 사용하면 화면 공간 비율을 기준으로 레이아웃 공간을 분할할 수 있습니다. Grid는 이러한 방식으로 공간을 나눌 수 있는 유일한 레이아웃 패널입니다.

모눈 정의 및 사용

다음 예제에서는 Windows 시작 메뉴에서 사용 가능한 실행 대화 상자에 있는 것과 유사한 UI를 빌드하는 방법을 보여 줍니다.

'Create a Grid as the root Panel element.
Dim myGrid As New Grid()
myGrid.Height = 165
myGrid.Width = 425
myGrid.Background = Brushes.Gainsboro
myGrid.ShowGridLines = True
myGrid.HorizontalAlignment = Windows.HorizontalAlignment.Left
myGrid.VerticalAlignment = Windows.VerticalAlignment.Top

' Define and Add the Rows and Columns.
Dim colDef1 As New ColumnDefinition
colDef1.Width = New GridLength(1, GridUnitType.Auto)
Dim colDef2 As New ColumnDefinition
colDef2.Width = New GridLength(1, GridUnitType.Star)
Dim colDef3 As New ColumnDefinition
colDef3.Width = New GridLength(1, GridUnitType.Star)
Dim colDef4 As New ColumnDefinition
colDef4.Width = New GridLength(1, GridUnitType.Star)
Dim colDef5 As New ColumnDefinition
colDef5.Width = New GridLength(1, GridUnitType.Star)
myGrid.ColumnDefinitions.Add(colDef1)
myGrid.ColumnDefinitions.Add(colDef2)
myGrid.ColumnDefinitions.Add(colDef3)
myGrid.ColumnDefinitions.Add(colDef4)
myGrid.ColumnDefinitions.Add(colDef5)

Dim rowDef1 As New RowDefinition
rowDef1.Height = New GridLength(1, GridUnitType.Auto)
Dim rowDef2 As New RowDefinition
rowDef2.Height = New GridLength(1, GridUnitType.Auto)
Dim rowDef3 As New Controls.RowDefinition
rowDef3.Height = New GridLength(1, GridUnitType.Star)
Dim rowDef4 As New RowDefinition
rowDef4.Height = New GridLength(1, GridUnitType.Auto)
myGrid.RowDefinitions.Add(rowDef1)
myGrid.RowDefinitions.Add(rowDef2)
myGrid.RowDefinitions.Add(rowDef3)
myGrid.RowDefinitions.Add(rowDef4)

' Add the Image.
Dim img1 As New Image
img1.Source = New System.Windows.Media.Imaging.BitmapImage(New Uri("runicon.png", UriKind.Relative))
Grid.SetRow(img1, 0)
Grid.SetColumn(img1, 0)
myGrid.Children.Add(img1)

' Add the main application dialog.
Dim txt1 As New TextBlock
txt1.Text = "Type the name of a program, document, or Internet resource, and Windows will open it for you."
txt1.TextWrapping = TextWrapping.Wrap
Grid.SetColumnSpan(txt1, 4)
Grid.SetRow(txt1, 0)
Grid.SetColumn(txt1, 1)
myGrid.Children.Add(txt1)

' Add the second TextBlock Cell to the Grid.
Dim txt2 As New TextBlock
txt2.Text = "Open:"
Grid.SetRow(txt2, 1)
Grid.SetColumn(txt2, 0)
myGrid.Children.Add(txt2)

' Add the TextBox control.
Dim tb1 As New TextBox
Grid.SetRow(tb1, 1)
Grid.SetColumn(tb1, 1)
Grid.SetColumnSpan(tb1, 5)
myGrid.Children.Add(tb1)

' Add the Button controls.
Dim button1 As New Button
Dim button2 As New Button
Dim button3 As New Button
button1.Content = "OK"
button1.Margin = New Thickness(10, 0, 10, 15)
button2.Content = "Cancel"
button2.Margin = New Thickness(10, 0, 10, 15)
button3.Content = "Browse ..."
button3.Margin = New Thickness(10, 0, 10, 15)

Grid.SetRow(button1, 3)
Grid.SetColumn(button1, 2)
Grid.SetRow(button2, 3)
Grid.SetColumn(button2, 3)
Grid.SetRow(button3, 3)
Grid.SetColumn(button3, 4)
myGrid.Children.Add(button1)
myGrid.Children.Add(button2)
myGrid.Children.Add(button3)

Me.Content = myGrid
// Create the Grid.
grid1 = new Grid ();
grid1.Background = Brushes.Gainsboro;
grid1.HorizontalAlignment = HorizontalAlignment.Left;
grid1.VerticalAlignment = VerticalAlignment.Top;
grid1.ShowGridLines = true;
grid1.Width = 425;
grid1.Height = 165;

// Define the Columns.
colDef1 = new ColumnDefinition();
colDef1.Width = new GridLength(1, GridUnitType.Auto);
colDef2 = new ColumnDefinition();
colDef2.Width = new GridLength(1, GridUnitType.Star);
colDef3 = new ColumnDefinition();
colDef3.Width = new GridLength(1, GridUnitType.Star);
colDef4 = new ColumnDefinition();
colDef4.Width = new GridLength(1, GridUnitType.Star);
colDef5 = new ColumnDefinition();
colDef5.Width = new GridLength(1, GridUnitType.Star);
grid1.ColumnDefinitions.Add(colDef1);
grid1.ColumnDefinitions.Add(colDef2);
grid1.ColumnDefinitions.Add(colDef3);
grid1.ColumnDefinitions.Add(colDef4);
grid1.ColumnDefinitions.Add(colDef5);

// Define the Rows.
rowDef1 = new RowDefinition();
rowDef1.Height = new GridLength(1, GridUnitType.Auto);
rowDef2 = new RowDefinition();
rowDef2.Height = new GridLength(1, GridUnitType.Auto);
rowDef3 = new RowDefinition();
rowDef3.Height = new GridLength(1, GridUnitType.Star);
rowDef4 = new RowDefinition();
rowDef4.Height = new GridLength(1, GridUnitType.Auto);
grid1.RowDefinitions.Add(rowDef1);
grid1.RowDefinitions.Add(rowDef2);
grid1.RowDefinitions.Add(rowDef3);
grid1.RowDefinitions.Add(rowDef4);

// Add the Image.
img1 = new Image();
img1.Source = new System.Windows.Media.Imaging.BitmapImage(new Uri("runicon.png", UriKind.Relative));
Grid.SetRow(img1, 0);
Grid.SetColumn(img1, 0);

// Add the main application dialog.
txt1 = new TextBlock();
txt1.Text = "Type the name of a program, folder, document, or Internet resource, and Windows will open it for you.";
txt1.TextWrapping = TextWrapping.Wrap;
Grid.SetColumnSpan(txt1, 4);
Grid.SetRow(txt1, 0);
Grid.SetColumn(txt1, 1);

// Add the second text cell to the Grid.
txt2 = new TextBlock();
txt2.Text = "Open:";
Grid.SetRow(txt2, 1);
Grid.SetColumn(txt2, 0);

// Add the TextBox control.
tb1 = new TextBox();
Grid.SetRow(tb1, 1);
Grid.SetColumn(tb1, 1);
Grid.SetColumnSpan(tb1, 5);

// Add the buttons.
button1 = new Button();
button2 = new Button();
button3 = new Button();
button1.Content = "OK";
button2.Content = "Cancel";
button3.Content = "Browse ...";
Grid.SetRow(button1, 3);
Grid.SetColumn(button1, 2);
button1.Margin = new Thickness(10, 0, 10, 15);
button2.Margin = new Thickness(10, 0, 10, 15);
button3.Margin = new Thickness(10, 0, 10, 15);
Grid.SetRow(button2, 3);
Grid.SetColumn(button2, 3);
Grid.SetRow(button3, 3);
Grid.SetColumn(button3, 4);

grid1.Children.Add(img1);
grid1.Children.Add(txt1);
grid1.Children.Add(txt2);
grid1.Children.Add(tb1);
grid1.Children.Add(button1);
grid1.Children.Add(button2);
grid1.Children.Add(button3);

mainWindow.Content = grid1;
<Page xmlns="https://schemas.microsoft.com/winfx/2006/xaml/presentation" 
      WindowTitle="Grid Run Dialog Sample" 
      WindowWidth="425" 
      WindowHeight="225">
  <Grid Background="#DCDCDC"
        Width="425"
        Height="165"
        HorizontalAlignment="Left"
        VerticalAlignment="Top"
        ShowGridLines="True">
    <Grid.ColumnDefinitions>
      <ColumnDefinition Width="Auto" />
      <ColumnDefinition Width="*" />
      <ColumnDefinition Width="*"/>
      <ColumnDefinition Width="*"/>
      <ColumnDefinition Width="*"/>
    </Grid.ColumnDefinitions>
    <Grid.RowDefinitions>
      <RowDefinition Height="Auto" />
      <RowDefinition Height="Auto" />
      <RowDefinition Height="*" />
      <RowDefinition Height="Auto" />
    </Grid.RowDefinitions>

    <Image Grid.Column="0" Grid.Row="0" Source="RunIcon.png" />
    <TextBlock Grid.Column="1" Grid.ColumnSpan="4" Grid.Row="0" TextWrapping="Wrap">
      Type the name of a program, folder, document, or
      Internet resource, and Windows will open it for you.
    </TextBlock>
    <TextBlock Grid.Column="0" Grid.Row="1">Open:</TextBlock>
    <TextBox Grid.Row="1" Grid.Column="1" Grid.ColumnSpan="5" />
    <Button Margin="10, 0, 10, 15" Grid.Row="3" Grid.Column="2">OK</Button>
    <Button Margin="10, 0, 10, 15" Grid.Row="3" Grid.Column="3">Cancel</Button>
    <Button Margin="10, 0, 10, 15" Grid.Row="3" Grid.Column="4">Browse ...</Button>
  </Grid>
</Page>

컴파일된 응용 프로그램은 다음과 같은 새 UI를 생성합니다.

일반적인 Grid 요소

StackPanel

StackPanel을 사용하면 요소를 할당된 방향으로 "쌓을" 수 있습니다. 기본 스택 방향은 수직입니다. Orientation 속성을 사용하면 콘텐츠의 흐름을 제어할 수 있습니다.

StackPanel과 DockPanel

DockPanel도 자식 요소를 "쌓을" 수는 있지만 DockPanelStackPanel은 일부 사용 시나리오에서 유사한 결과를 생성하지 않습니다. 예를 들어 자식 요소의 순서가 DockPanel에서는 자식 요소의 크기에 영향을 주지만 StackPanel에서는 그렇지 않을 수 있습니다. StackPanelPositiveInfinity에서 쌓는 방향으로 측정하지만 DockPanel은 사용 가능한 크기만 측정하기 때문에 이러한 동작 차이가 발생합니다.

다음 예제에서는 이러한 주요 차이를 보여 줍니다.

'Add root Grid
Dim myGrid As New Grid
myGrid.Width = 175
myGrid.Height = 150
Dim myRowDef1 As New RowDefinition
Dim myRowDef2 As New RowDefinition
myGrid.RowDefinitions.Add(myRowDef1)
myGrid.RowDefinitions.Add(myRowDef2)

'Define the DockPanel
Dim myDockPanel As New DockPanel
Grid.SetRow(myDockPanel, 0)

'Define an Image and Source.
Dim myImage As New Image
Dim bi As New BitmapImage
bi.BeginInit()
bi.UriSource = New Uri("smiley_stackpanel.png", UriKind.Relative)
bi.EndInit()
myImage.Source = bi

Dim myImage2 As New Image
Dim bi2 As New BitmapImage
bi2.BeginInit()
bi2.UriSource = New Uri("smiley_stackpanel.png", UriKind.Relative)
bi2.EndInit()
myImage2.Source = bi2

Dim myImage3 As New Image
Dim bi3 As New BitmapImage
bi3.BeginInit()
bi3.UriSource = New Uri("smiley_stackpanel.PNG", UriKind.Relative)
bi3.EndInit()
myImage3.Stretch = Stretch.Fill
myImage3.Source = bi3

'Add the images to the parent DockPanel.
myDockPanel.Children.Add(myImage)
myDockPanel.Children.Add(myImage2)
myDockPanel.Children.Add(myImage3)

'Define a StackPanel.
Dim myStackPanel As New StackPanel
myStackPanel.Orientation = Orientation.Horizontal
Grid.SetRow(myStackPanel, 1)

Dim myImage4 As New Image
Dim bi4 As New BitmapImage
bi4.BeginInit()
bi4.UriSource = New Uri("smiley_stackpanel.png", UriKind.Relative)
bi4.EndInit()
myImage4.Source = bi4

Dim myImage5 As New Image
Dim bi5 As New BitmapImage
bi5.BeginInit()
bi5.UriSource = New Uri("smiley_stackpanel.png", UriKind.Relative)
bi5.EndInit()
myImage5.Source = bi5

Dim myImage6 As New Image
Dim bi6 As New BitmapImage
bi6.BeginInit()
bi6.UriSource = New Uri("smiley_stackpanel.PNG", UriKind.Relative)
bi6.EndInit()
myImage6.Stretch = Stretch.Fill
myImage6.Source = bi6

'Add the images to the parent StackPanel.
myStackPanel.Children.Add(myImage4)
myStackPanel.Children.Add(myImage5)
myStackPanel.Children.Add(myImage6)

'Add the layout panels as children of the Grid
myGrid.Children.Add(myDockPanel)
myGrid.Children.Add(myStackPanel)

// Create the application's main window
mainWindow = new Window ();
mainWindow.Title = "StackPanel vs. DockPanel";

// Add root Grid
myGrid = new Grid();
myGrid.Width = 175;
myGrid.Height = 150;
RowDefinition myRowDef1 = new RowDefinition();
RowDefinition myRowDef2 = new RowDefinition();
myGrid.RowDefinitions.Add(myRowDef1);
myGrid.RowDefinitions.Add(myRowDef2);

// Define the DockPanel
myDockPanel = new DockPanel();
Grid.SetRow(myDockPanel, 0);

//Define an Image and Source
Image myImage = new Image();
BitmapImage bi = new BitmapImage();
bi.BeginInit();
bi.UriSource = new Uri("smiley_stackpanel.png", UriKind.Relative);
bi.EndInit();
myImage.Source = bi;

Image myImage2 = new Image();
BitmapImage bi2 = new BitmapImage();
bi2.BeginInit();
bi2.UriSource = new Uri("smiley_stackpanel.png", UriKind.Relative);
bi2.EndInit();
myImage2.Source = bi2;

Image myImage3 = new Image();
BitmapImage bi3 = new BitmapImage();
bi3.BeginInit();
bi3.UriSource = new Uri("smiley_stackpanel.PNG", UriKind.Relative);
bi3.EndInit();
myImage3.Stretch = Stretch.Fill;
myImage3.Source = bi3;

// Add the images to the parent DockPanel
myDockPanel.Children.Add(myImage);
myDockPanel.Children.Add(myImage2);
myDockPanel.Children.Add(myImage3);

//Define a StackPanel
myStackPanel = new StackPanel();
myStackPanel.Orientation = Orientation.Horizontal;
Grid.SetRow(myStackPanel, 1);

Image myImage4 = new Image();
BitmapImage bi4 = new BitmapImage();
bi4.BeginInit();
bi4.UriSource = new Uri("smiley_stackpanel.png", UriKind.Relative);
bi4.EndInit();
myImage4.Source = bi4;

Image myImage5 = new Image();
BitmapImage bi5 = new BitmapImage();
bi5.BeginInit();
bi5.UriSource = new Uri("smiley_stackpanel.png", UriKind.Relative);
bi5.EndInit();
myImage5.Source = bi5;

Image myImage6 = new Image();
BitmapImage bi6 = new BitmapImage();
bi6.BeginInit();
bi6.UriSource = new Uri("smiley_stackpanel.PNG", UriKind.Relative);
bi6.EndInit();
myImage6.Stretch = Stretch.Fill;
myImage6.Source = bi6;

// Add the images to the parent StackPanel
myStackPanel.Children.Add(myImage4);
myStackPanel.Children.Add(myImage5);
myStackPanel.Children.Add(myImage6);

// Add the layout panels as children of the Grid
myGrid.Children.Add(myDockPanel);
myGrid.Children.Add(myStackPanel);

// Add the Grid as the Content of the Parent Window Object
mainWindow.Content = myGrid;
mainWindow.Show ();

<Page xmlns="https://schemas.microsoft.com/winfx/2006/xaml/presentation"
      WindowTitle="StackPanel vs. DockPanel">
  <Grid Width="175" Height="150">
    <Grid.ColumnDefinitions>
      <ColumnDefinition />
    </Grid.ColumnDefinitions>
    <Grid.RowDefinitions>
      <RowDefinition />
      <RowDefinition />
    </Grid.RowDefinitions>

    <DockPanel Grid.Column="0" Grid.Row="0">
      <Image Source="smiley_stackpanel.png" />
      <Image Source="smiley_stackpanel.png" />
      <Image Source="smiley_stackpanel.png" Stretch="Fill"/>
    </DockPanel>

    <StackPanel Grid.Column="0" Grid.Row="1"  Orientation="Horizontal">
      <Image Source="smiley_stackpanel.png" />
      <Image Source="smiley_stackpanel.png" />
      <Image Source="smiley_stackpanel.png" Stretch="Fill"/>
    </StackPanel>
    </Grid>
</Page>

렌더링 동작 차이는 다음 그림에서 확인할 수 있습니다.

스크린 샷: StackPanel 및 DockPanel 스크린 샷

StackPanel 정의 및 사용

다음 예제에서는 StackPanel을 사용하여 세로 방향으로 배치된 단추 집합을 만드는 방법을 보여 줍니다. 가로 방향으로 배치하려면 Orientation 속성을 Horizontal로 설정합니다.

WindowTitle = "StackPanel Sample"
' Define the StackPanel
Dim myStackPanel As New StackPanel()
myStackPanel.HorizontalAlignment = Windows.HorizontalAlignment.Left
myStackPanel.VerticalAlignment = Windows.VerticalAlignment.Top

' Define child content
Dim myButton1 As New Button()
myButton1.Content = "Button 1"
Dim myButton2 As New Button()
myButton2.Content = "Button 2"
Dim myButton3 As New Button()
myButton3.Content = "Button 3"

' Add child elements to the parent StackPanel
myStackPanel.Children.Add(myButton1)
myStackPanel.Children.Add(myButton2)
myStackPanel.Children.Add(myButton3)

Me.Content = myStackPanel
// Create the application's main window
mainWindow = new Window ();
mainWindow.Title = "StackPanel Sample";

// Define the StackPanel
myStackPanel = new StackPanel();
myStackPanel.HorizontalAlignment = HorizontalAlignment.Left;
myStackPanel.VerticalAlignment = VerticalAlignment.Top;

// Define child content
Button myButton1 = new Button();
myButton1.Content = "Button 1";
Button myButton2 = new Button();
myButton2.Content = "Button 2";
Button myButton3 = new Button();
myButton3.Content = "Button 3";

// Add child elements to the parent StackPanel
myStackPanel.Children.Add(myButton1);
myStackPanel.Children.Add(myButton2);
myStackPanel.Children.Add(myButton3);           

// Add the StackPanel as the Content of the Parent Window Object
mainWindow.Content = myStackPanel;
mainWindow.Show ();

<Page xmlns="https://schemas.microsoft.com/winfx/2006/xaml/presentation" WindowTitle="StackPanel Sample">
    <StackPanel HorizontalAlignment="Left"
                VerticalAlignment="Top">
        <Button>Button 1</Button>
        <Button>Button 2</Button>
        <Button>Button 3</Button>
    </StackPanel>
</Page>

컴파일된 응용 프로그램은 다음과 같은 새 UI를 생성합니다.

일반적인 StackPanel 요소

VirtualizingStackPanel

또한 WPF에서는 데이터 바인딩된 자식 콘텐츠를 자동으로 "가상화"하는 StackPanel 요소의 변형을 제공합니다. 여기서 가상화라는 단어는 화면에 표시되는 항목에 따라 많은 수의 데이터 항목에서 UIElements의 하위 집합이 생성되는 기술을 가리킵니다. 특정 시점에 화면에 표시되는 것보다 많은 개수의 UI 요소를 생성하는 것은 메모리 및 프로세서 측면에서 비효율적입니다. VirtualizingPanel이 제공하는 기능을 통해 VirtualizingStackPanel은 표시되는 항목을 계산하고, ListBox 또는 ListView와 같은 ItemsControlItemContainerGenerator를 사용하여 표시되는 항목에 대한 UIElements만 만듭니다.

VirtualizingStackPanel 요소는 ListBox와 같은 컨트롤에 대한 항목 호스트로 자동 설정됩니다. 데이터 바인딩된 컬렉션을 호스팅하는 경우 콘텐츠가 ScrollViewer의 범위 내에 있으면 콘텐츠는 자동으로 가상화됩니다. 이렇게 하면 많은 자식 항목을 호스팅하는 경우 성능이 크게 개선됩니다.

다음 태그에서는 VirtualizingStackPanel을 항목 호스트로 사용하는 방법을 보여 줍니다. 가상화가 발생하려면 IsVirtualizing 연결된 속성을 True(기본값)로 설정해야 합니다.

<StackPanel DataContext="{Binding Source={StaticResource Leagues}}">
    <TextBlock Text="{Binding XPath=@name}" FontFamily="Arial" FontSize="18" Foreground="Black"/>
        <ListBox VirtualizingStackPanel.IsVirtualizing="True" 
                 ItemsSource="{Binding XPath=Team}" 
                 ItemTemplate="{DynamicResource NameDataStyle}"/>      
</StackPanel>

WrapPanel

WrapPanel은 자식 요소를 왼쪽에서 오른쪽으로 순차적으로 배치하고, 해당 부모 컨테이너의 가장자리에 도달할 경우 내용을 다음 줄로 바꾸는 데 사용됩니다. 콘텐츠는 가로 또는 세로 방향으로 지정할 수 있습니다. WrapPanel은 간단한 유동 UI(사용자 인터페이스) 시나리오에 유용하며 모든 해당 자식 요소에 동일한 크기를 적용하는 데에도 사용될 수 있습니다.

다음 예제에서는 해당 컨테이너의 가장자리에 도달할 경우 줄을 바꾸는 Button 컨트롤을 표시하는 WrapPanel을 만드는 방법을 보여 줍니다.

WindowTitle = "WrapPanel Sample"

' Instantiate a new WrapPanel and set properties
Dim myWrapPanel As New WrapPanel()
myWrapPanel.Background = Brushes.Azure
myWrapPanel.Orientation = Orientation.Horizontal
myWrapPanel.ItemHeight = 25

myWrapPanel.ItemWidth = 75
myWrapPanel.Width = 150
myWrapPanel.HorizontalAlignment = Windows.HorizontalAlignment.Left
myWrapPanel.VerticalAlignment = Windows.VerticalAlignment.Top

' Define 3 button elements. Each button is sized at width of 75, so the third button wraps to the next line.
Dim btn1 As New Button()
btn1.Content = "Button 1"
Dim btn2 As New Button()
btn2.Content = "Button 2"
Dim btn3 As New Button()
btn3.Content = "Button 3"

' Add the buttons to the parent WrapPanel using the Children.Add method.
myWrapPanel.Children.Add(btn1)
myWrapPanel.Children.Add(btn2)
myWrapPanel.Children.Add(btn3)

' Add the WrapPanel to the Page as Content
Me.Content = myWrapPanel

            // Create the application's main window
            mainWindow = new System.Windows.Window();
            mainWindow.Title = "WrapPanel Sample";


            // Instantiate a new WrapPanel and set properties
            myWrapPanel = new WrapPanel();
            myWrapPanel.Background = System.Windows.Media.Brushes.Azure;
            myWrapPanel.Orientation = Orientation.Horizontal;
            myWrapPanel.ItemHeight = 25;

            myWrapPanel.ItemWidth = 75;
            myWrapPanel.Width = 150;
            myWrapPanel.HorizontalAlignment = HorizontalAlignment.Left;
            myWrapPanel.VerticalAlignment = VerticalAlignment.Top;

            // Define 3 button elements. Each button is sized at width of 75, so the third button wraps to the next line.
            btn1 = new Button();
            btn1.Content = "Button 1";
            btn2 = new Button();
            btn2.Content = "Button 2";
            btn3 = new Button();
            btn3.Content = "Button 3";

            // Add the buttons to the parent WrapPanel using the Children.Add method.
            myWrapPanel.Children.Add(btn1);
            myWrapPanel.Children.Add(btn2);
            myWrapPanel.Children.Add(btn3);

            // Add the WrapPanel to the MainWindow as Content
            mainWindow.Content = myWrapPanel;
            mainWindow.Show();

<Page xmlns="https://schemas.microsoft.com/winfx/2006/xaml/presentation" WindowTitle="WrapPanel Sample">
  <Border HorizontalAlignment="Left" VerticalAlignment="Top" BorderBrush="Black" BorderThickness="2">
        <WrapPanel Background="LightBlue" Width="200" Height="100">
            <Button Width="200">Button 1</Button>
            <Button>Button 2</Button>
            <Button>Button 3</Button>
            <Button>Button 4</Button>
        </WrapPanel>
  </Border>    
</Page>

컴파일된 응용 프로그램은 다음과 같은 새 UI를 생성합니다.

일반적인 WrapPanel 요소

중첩 Panel 요소

Panel 요소를 각 해당 요소 내에 중첩시켜 복잡한 레이아웃을 생성할 수 있습니다. 이렇게 하면 UI 부분에 하나의 Panel이 적절한 경우 매우 유용하지만 다양한 UI 부분의 요구에는 맞지 않을 수 있습니다.

응용 프로그램에서 지원할 수 있는 중첩의 양에는 사실상 제한이 없지만 원하는 레이아웃에 대해 실제로 필요한 패널만 사용하도록 응용 프로그램을 제한하는 것이 일반적으로 가장 좋습니다. 대부분의 경우 융통성을 위해 중첩 패널 대신 Grid 요소를 레이아웃 컨테이너로 사용합니다. 이렇게 하면 불필요한 요소를 트리에서 제외하여 응용 프로그램 성능이 향상됩니다.

다음 예제에서는 특정 레이아웃을 만들기 위해 중첩 Panel 요소를 활용하는 UI를 만드는 방법을 보여 줍니다. 여기서는 UI 구조체를 제공하는 데 DockPanel 요소를 사용하고 부모 DockPanel 내에 자식 요소를 정확하게 배치하는 데 중첩 StackPanel 요소, GridCanvas를 사용합니다.

Dim myDockPanel As New DockPanel()

Dim myBorder2 As New Border()
myBorder2.BorderThickness = New Thickness(1)
myBorder2.BorderBrush = Brushes.Black
DockPanel.SetDock(myBorder2, Dock.Left)
Dim myStackPanel As New StackPanel()
Dim myButton1 As New Button()
myButton1.Content = "Left Docked"
myButton1.Margin = New Thickness(5)
Dim myButton2 As New Button()
myButton2.Content = "StackPanel"
myButton2.Margin = New Thickness(5)
myStackPanel.Children.Add(myButton1)
myStackPanel.Children.Add(myButton2)
myBorder2.Child = myStackPanel

Dim myBorder3 As New Border()
myBorder3.BorderThickness = New Thickness(1)
myBorder3.BorderBrush = Brushes.Black
DockPanel.SetDock(myBorder3, Dock.Top)
Dim myGrid As New Grid()
myGrid.ShowGridLines = True
Dim myRowDef1 As New RowDefinition()
Dim myRowDef2 As New RowDefinition()
Dim myColDef1 As New ColumnDefinition()
Dim myColDef2 As New ColumnDefinition()
Dim myColDef3 As New ColumnDefinition()
myGrid.ColumnDefinitions.Add(myColDef1)
myGrid.ColumnDefinitions.Add(myColDef2)
myGrid.ColumnDefinitions.Add(myColDef3)
myGrid.RowDefinitions.Add(myRowDef1)
myGrid.RowDefinitions.Add(myRowDef2)
Dim myTextBlock1 As New TextBlock()
myTextBlock1.FontSize = 20
myTextBlock1.Margin = New Thickness(10)
myTextBlock1.Text = "Grid Element Docked at the Top"
Grid.SetRow(myTextBlock1, 0)
Grid.SetColumnSpan(myTextBlock1, 3)
Dim myButton3 As New Button()
myButton3.Margin = New Thickness(5)
myButton3.Content = "A Row"
Grid.SetColumn(myButton3, 0)
Grid.SetRow(myButton3, 1)
Dim myButton4 As New Button()
myButton4.Margin = New Thickness(5)
myButton4.Content = "of Button"
Grid.SetColumn(myButton4, 1)
Grid.SetRow(myButton4, 1)
Dim myButton5 As New Button()
myButton5.Margin = New Thickness(5)
myButton5.Content = "Elements"
Grid.SetColumn(myButton5, 2)
Grid.SetRow(myButton5, 1)
myGrid.Children.Add(myTextBlock1)
myGrid.Children.Add(myButton3)
myGrid.Children.Add(myButton4)
myGrid.Children.Add(myButton5)
myBorder3.Child = myGrid

Dim myBorder4 As New Border()
myBorder4.BorderBrush = Brushes.Black
myBorder4.BorderThickness = New Thickness(1)
DockPanel.SetDock(myBorder4, Dock.Bottom)
Dim myStackPanel2 As New StackPanel()
myStackPanel2.Orientation = Orientation.Horizontal
Dim myTextBlock2 As New TextBlock()
myTextBlock2.Text = "This StackPanel is Docked to the Bottom"
myTextBlock2.Margin = New Thickness(5)
myStackPanel2.Children.Add(myTextBlock2)
myBorder4.Child = myStackPanel2

Dim myBorder5 As New Border()
myBorder5.BorderBrush = Brushes.Black
myBorder5.BorderThickness = New Thickness(1)
Dim myCanvas As New Canvas()
myCanvas.ClipToBounds = True
Dim myTextBlock3 As New TextBlock()
myTextBlock3.Text = "Content in the Canvas will Fill the remaining space."
Canvas.SetTop(myTextBlock3, 50)
Canvas.SetLeft(myTextBlock3, 50)
Dim myEllipse As New Ellipse()
myEllipse.Height = 100
myEllipse.Width = 125
myEllipse.Fill = Brushes.CornflowerBlue
myEllipse.Stroke = Brushes.Aqua
Canvas.SetTop(myEllipse, 100)
Canvas.SetLeft(myEllipse, 150)
myCanvas.Children.Add(myTextBlock3)
myCanvas.Children.Add(myEllipse)
myBorder5.Child = myCanvas

myDockPanel.Children.Add(myBorder2)
myDockPanel.Children.Add(myBorder3)
myDockPanel.Children.Add(myBorder4)
myDockPanel.Children.Add(myBorder5)
// Define the DockPanel.
myDockPanel = new DockPanel();

// Add the Left Docked StackPanel
Border myBorder2 = new Border();
myBorder2.BorderThickness = new Thickness(1);
myBorder2.BorderBrush = Brushes.Black;
DockPanel.SetDock(myBorder2, Dock.Left);
StackPanel myStackPanel = new StackPanel();
Button myButton1 = new Button();
myButton1.Content = "Left Docked";
myButton1.Margin = new Thickness(5);
Button myButton2 = new Button();
myButton2.Content = "StackPanel";
myButton2.Margin = new Thickness(5);
myStackPanel.Children.Add(myButton1);
myStackPanel.Children.Add(myButton2);
myBorder2.Child = myStackPanel;

// Add the Top Docked Grid.
Border myBorder3 = new Border();
myBorder3.BorderThickness = new Thickness(1);
myBorder3.BorderBrush = Brushes.Black;
DockPanel.SetDock(myBorder3, Dock.Top);
Grid myGrid = new Grid();
myGrid.ShowGridLines = true;
RowDefinition myRowDef1 = new RowDefinition();
RowDefinition myRowDef2 = new RowDefinition();
ColumnDefinition myColDef1 = new ColumnDefinition();
ColumnDefinition myColDef2 = new ColumnDefinition();
ColumnDefinition myColDef3 = new ColumnDefinition();
myGrid.ColumnDefinitions.Add(myColDef1);
myGrid.ColumnDefinitions.Add(myColDef2);
myGrid.ColumnDefinitions.Add(myColDef3);
myGrid.RowDefinitions.Add(myRowDef1);
myGrid.RowDefinitions.Add(myRowDef2);
TextBlock myTextBlock1 = new TextBlock();
myTextBlock1.FontSize = 20;
myTextBlock1.Margin = new Thickness(10);
myTextBlock1.Text = "Grid Element Docked at the Top";
Grid.SetRow(myTextBlock1, 0);
Grid.SetColumnSpan(myTextBlock1, 3);
Button myButton3 = new Button();
myButton3.Margin = new Thickness(5);
myButton3.Content = "A Row";
Grid.SetColumn(myButton3, 0);
Grid.SetRow(myButton3, 1);
Button myButton4 = new Button();
myButton4.Margin = new Thickness(5);
myButton4.Content = "of Button";
Grid.SetColumn(myButton4, 1);
Grid.SetRow(myButton4, 1);
Button myButton5 = new Button();
myButton5.Margin = new Thickness(5);
myButton5.Content = "Elements";
Grid.SetColumn(myButton5, 2);
Grid.SetRow(myButton5, 1);
myGrid.Children.Add(myTextBlock1);
myGrid.Children.Add(myButton3);
myGrid.Children.Add(myButton4);
myGrid.Children.Add(myButton5);
myBorder3.Child = myGrid;

// Add the Bottom Docked StackPanel.
Border myBorder4 = new Border();
myBorder4.BorderBrush = Brushes.Black;
myBorder4.BorderThickness = new Thickness(1);
DockPanel.SetDock(myBorder4, Dock.Bottom);
StackPanel myStackPanel2 = new StackPanel();
myStackPanel2.Orientation = Orientation.Horizontal;
TextBlock myTextBlock2 = new TextBlock();
myTextBlock2.Text = "This StackPanel is Docked to the Bottom";
myTextBlock2.Margin = new Thickness(5);
myStackPanel2.Children.Add(myTextBlock2);
myBorder4.Child = myStackPanel2;

// Add the Canvas, that fills remaining space.
Border myBorder5 = new Border();
myBorder4.BorderBrush = Brushes.Black;
myBorder5.BorderThickness = new Thickness(1);
Canvas myCanvas = new Canvas();
myCanvas.ClipToBounds = true;
TextBlock myTextBlock3 = new TextBlock();
myTextBlock3.Text = "Content in the Canvas will Fill the remaining space.";
Canvas.SetTop(myTextBlock3, 50);
Canvas.SetLeft(myTextBlock3, 50);
Ellipse myEllipse = new Ellipse();
myEllipse.Height = 100;
myEllipse.Width = 125;
myEllipse.Fill = Brushes.CornflowerBlue;
myEllipse.Stroke = Brushes.Aqua;
Canvas.SetTop(myEllipse, 100);
Canvas.SetLeft(myEllipse, 150);
myCanvas.Children.Add(myTextBlock3);
myCanvas.Children.Add(myEllipse);
myBorder5.Child = myCanvas;

// Add child elements to the parent DockPanel.
myDockPanel.Children.Add(myBorder2);
myDockPanel.Children.Add(myBorder3);
myDockPanel.Children.Add(myBorder4);
myDockPanel.Children.Add(myBorder5);
<Page xmlns="https://schemas.microsoft.com/winfx/2006/xaml/presentation" WindowTitle="Nested Panels">
  <Border Background="AliceBlue" 
          Width="400" 
          Height="300" 
          BorderBrush="DarkSlateBlue" 
          BorderThickness="2"
          HorizontalAlignment="Left" 
          VerticalAlignment="Top">
    <DockPanel>
      <Border BorderBrush="Black" BorderThickness="1" DockPanel.Dock="Left">
        <StackPanel>
          <Button Margin="5">Left Docked</Button>
          <Button Margin="5">StackPanel</Button>
        </StackPanel>
      </Border>
      <Border BorderBrush="Black" BorderThickness="1" DockPanel.Dock="Top">
        <Grid ShowGridLines="True">
          <Grid.RowDefinitions>
            <RowDefinition/>
            <RowDefinition/>
          </Grid.RowDefinitions>
          <Grid.ColumnDefinitions>
            <ColumnDefinition />
            <ColumnDefinition />
            <ColumnDefinition />
          </Grid.ColumnDefinitions>
          <TextBlock FontSize="20" Margin="10" Grid.ColumnSpan="3" Grid.Row="0">Grid Element Docked to the Top.</TextBlock>
          <Button Grid.Row="1" Grid.Column="0" Margin="5">A Row</Button>
          <Button Grid.Row="1" Grid.Column="1" Margin="5">of Button</Button>
          <Button Grid.Row="1" Grid.Column="2" Margin="5">Elements</Button>
        </Grid>
      </Border>
      <Border BorderBrush="Black" BorderThickness="1" DockPanel.Dock="Bottom">
        <StackPanel Orientation="Horizontal">
          <TextBlock Margin="5">This StackPanel is Docked to the Bottom.</TextBlock>
        </StackPanel>
      </Border>
      <Border BorderBrush="Black" BorderThickness="1">
        <Canvas ClipToBounds="True">
          <TextBlock Canvas.Top="50" Canvas.Left="50">
            Content in the Canvas will Fill the remaining Space.
          </TextBlock>
          <Ellipse Height="100" Width="125" Fill="CornflowerBlue" Stroke="Aqua" Canvas.Top="100" Canvas.Left="150"/>
        </Canvas>
      </Border>
    </DockPanel>
  </Border>
</Page>

컴파일된 응용 프로그램은 다음과 같은 새 UI를 생성합니다.

중첩된 패널의 이점을 활용하는 UI

사용자 지정 Panel 요소

WPF는 유연한 레이아웃 컨트롤 배열을 제공하지만 ArrangeOverrideMeasureOverride 메서드를 재정의하여 사용자 지정 레이아웃 동작을 얻을 수도 있습니다. 사용자 지정 크기 조정 및 위치 지정은 이러한 재정의 메서드 내에서 새 위치 지정 동작을 정의하여 수행할 수 있습니다.

마찬가지로 Canvas 또는 Grid와 같은 파생 클래스를 기반으로 하는 사용자 지정 레이아웃 동작을 해당 ArrangeOverrideMeasureOverride 메서드를 재정의하여 정의할 수 있습니다.

다음 태그에서는 C#을 사용하여 사용자 지정 Panel 요소를 만드는 방법을 보여 줍니다. PlotPanel로 정의된 이 새 Panel은 하드 코드된 x 좌표 및 y 좌표를 사용하여 자식 요소의 위치를 지정하는 작업을 지원합니다. 이 예제에서 표시되지 않은 Rectangle 요소는 그림 지점 50(x), 50(y)에 배치됩니다.

Public Class PlotPanel
    Inherits Panel
    'Override the default Measure method of Panel.

    Protected Overrides Function MeasureOverride(ByVal availableSize As System.Windows.Size) As System.Windows.Size
        Dim childSize As Size = CType(availableSize, Size)
        For Each child As UIElement In InternalChildren
            child.Measure(childSize)
        Next
        Return MyBase.MeasureOverride(availableSize)
    End Function
    Protected Overrides Function ArrangeOverride(ByVal finalSize As System.Windows.Size) As System.Windows.Size
        For Each child As UIElement In InternalChildren
            Dim x As Double = 50
            Dim y As Double = 50
            child.Arrange(New Rect(New System.Windows.Point(x, y), child.DesiredSize))
        Next
        Return MyBase.ArrangeOverride(finalSize)
    End Function
End Class
public class PlotPanel : Panel
{
    // Default public constructor
    public PlotPanel()
        : base()
    {
    }

    // Override the default Measure method of Panel
    protected override Size MeasureOverride(Size availableSize)
    {
        Size panelDesiredSize = new Size();

        // In our example, we just have one child. 
        // Report that our panel requires just the size of its only child.
        foreach (UIElement child in InternalChildren)
        {
            child.Measure(availableSize);
            panelDesiredSize = child.DesiredSize;
        }

        return panelDesiredSize ;
    }
    protected override Size ArrangeOverride(Size finalSize)
    {
        foreach (UIElement child in InternalChildren)
        {
            double x = 50;
            double y = 50;

            child.Arrange(new Rect(new Point(x, y), child.DesiredSize));
        }
        return finalSize; // Returns the final Arranged size
    }
}

전체 샘플을 보려면 간단한 사용자 지정 패널 만들기 샘플을 참조하십시오.

더 복잡한 사용자 지정 패널 구현을 보려면 사용자 지정 콘텐츠 줄 바꿈 패널 만들기 샘플을 참조하십시오.

지역화/전역화 지원

WPF는 지역화할 수 있는 UI 생성에 도움이 되는 여러 가지 기능을 지원합니다.

모든 패널은 사용자의 로캘 또는 언어 설정에 따라 동적으로 콘텐츠의 흐름을 변경하는 데 사용할 수 있는 FlowDirection 속성을 기본적으로 지원합니다. 자세한 내용은 FlowDirection을 참조하십시오.

SizeToContent 속성은 응용 프로그램 개발자가 지역화된 UI의 요구를 예상할 수 있도록 하는 메커니즘을 제공합니다. 이 속성의 WidthAndHeight 값을 사용하면 부모 Window의 크기가 콘텐츠에 맞게 동적으로 조정되며 해당 창에 인위적인 높이 또는 너비 제한이 적용되지 않습니다.

DockPanel, GridStackPanel은 모두 지역화할 수 있는 UI에 대해 적합한 선택입니다. 그러나 Canvas는 콘텐츠를 절대 배치하여 지역화하기가 힘들어지기 때문에 적합한 선택이 아닙니다.

지역화할 수 있는 UI(사용자 인터페이스)가 있는 WPF 응용 프로그램을 만드는 방법에 대한 자세한 내용은 자동 레이아웃 사용 개요를 참조하십시오.

참고 항목

작업

WPF 레이아웃 갤러리 샘플

WPF 컨트롤 갤러리 샘플

사용자 지정 콘텐츠 줄 바꿈 패널 만들기 샘플

개념

Windows Presentation Foundation 시작

레이아웃 시스템

맞춤, 여백 및 안쪽 여백 개요

연결된 속성 개요

자동 레이아웃 사용 개요

성능 최적화: 레이아웃 및 디자인