Panel 개요

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

이 항목에는 다음과 같은 섹션이 포함되어 있습니다.

Panel 클래스

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

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

패널의 공통 멤버

모든 Panel 요소는 Height, Width, HorizontalAlignment, VerticalAlignment, MarginLayoutTransform과 같이 FrameworkElement를 통해 정의된 기본 크기 조정 및 분할 속성을 지원합니다. FrameworkElement를 통해 정의된 분할 속성을 배치하는 방법에 대한 자세한 내용은 맞춤, 여백 및 안쪽 여백 개요를 참조하세요.

Panel은 레이아웃을 이해하고 사용하는 데 매우 중요한 추가 속성을 표시합니다. Background 속성은 파생 패널 요소의 경계 사이에 있는 영역을 Brush로 채우는 데 사용됩니다. ChildrenPanel을 구성하는 요소의 자식 컬렉션을 나타냅니다. InternalChildrenChildren 컬렉션의 콘텐츠 및 데이터 바인딩에서 생성된 멤버를 나타냅니다. 두 항목은 모두 부모 Panel 내에 호스트되는 자식 요소의 UIElementCollection으로 구성됩니다.

패널은 파생 Panel에서 겹쳐진 순서를 적용하는 데 사용될 수 있는 Panel.ZIndex 연결된 속성을 표시합니다. Panel.ZIndex 값이 더 큰 패널의 Children 컬렉션 멤버는 Panel.ZIndex 값이 더 작은 컬렉션 멤버 앞에 표시됩니다. 이 기능은 자식이 같은 좌표 공간을 공유할 수 있는 CanvasGrid와 같은 패널에 특히 유용합니다.

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

연결된 속성

파생 패널 요소는 연결된 속성을 광범위하게 사용합니다. 연결된 속성은 기존 CLR(공용 언어 런타임) 속성 "래퍼"가 없는 종속성 속성의 특수 형식입니다. 연결된 속성에는 다음 여러 예제에서 확인할 수 있는 XAML(Extensible Application Markup Language)의 특수 구문이 있습니다.

연결된 속성의 한 가지 목적은 자식 요소가 부모 요소를 통해 실제로 정의되는 속성의 고유 값을 저장하도록 하는 것입니다. 이 기능을 제공하는 애플리케이션에서는 자식 요소가 자신이 UI(사용자 인터페이스)에 표시되는 방식을 부모에게 알립니다. 이 기능은 애플리케이션 레이아웃에 매우 유용합니다. 자세한 내용은 연결된 속성 개요를 참조하세요.

파생 패널 요소

많은 개체가 Panel에서 파생되지만 이들 개체 중 일부는 루트 레이아웃 공급자로 사용되지 않습니다. 애플리케이션 UI를 만들기 위해 특별히 설계된 6개의 정의된 패널 클래스(Canvas, DockPanel, Grid, StackPanel, VirtualizingStackPanelWrapPanel)가 있습니다.

각 패널 요소는 다음 테이블에 나와 있는 자체 특수 기능을 캡슐화합니다.

요소 이름 UI 패널 여부 Description
Canvas Canvas 영역에 상대적인 좌표를 사용하여 자식 요소를 명시적으로 배치할 수 있는 영역을 정의합니다.
DockPanel 자식 요소를 서로 맞춰 가로 또는 세로로 정렬할 수 있는 영역을 정의합니다.
Grid 열 및 행으로 구성되는 유연한 그리드 영역을 정의합니다. Grid의 자식 요소는 Margin 속성을 사용하여 세밀하게 위치를 지정할 수 있습니다.
StackPanel 가로 또는 세로 방향으로 한 줄로 자식 요소를 정렬합니다.
TabPanel TabControl에서 탭 단추의 레이아웃을 처리합니다.
ToolBarOverflowPanel ToolBar 컨트롤 내에서 콘텐츠를 정렬합니다.
UniformGrid 아니요 UniformGrid는 셀 크기가 모두 같은 그리드에서 자식을 정렬하는 데 사용됩니다.
VirtualizingPanel 아니요 자식 컬렉션을 "가상화"할 수 있는 패널의 기본 클래스를 제공합니다.
VirtualizingStackPanel 가로 또는 세로 방향으로 한 줄로 콘텐츠를 정렬하고 가상화합니다.
WrapPanel WrapPanel은 콘텐츠를 컨테이너의 가장자리에서 다음 줄로 나눠 왼쪽에서 오른쪽으로 자식 요소의 위치를 지정합니다. 이후에는 Orientation 속성 값에 따라 순서가 위에서 아래로 또는 오른쪽에서 왼쪽으로 순차적으로 지정됩니다.

사용자 인터페이스 패널

WPF에는 UI 시나리오를 지원하도록 최적화된 6개의 패널 클래스, 즉 Canvas, DockPanel, Grid, StackPanel, VirtualizingStackPanel, WrapPanel이 있습니다. 이러한 패널 요소는 쉽게 사용할 수 있고, 유연하고, 대부분 애플리케이션용으로 충분히 확장 가능합니다.

각 파생 Panel 요소는 크기 조정 제약 조건을 다르게 처리합니다. Panel이 제약 조건을 가로 또는 세로 방향으로 처리하는 방법을 이해하면 레이아웃을 더 정확히 예측할 수 있습니다.

패널 이름 x 차원 y 차원
Canvas 콘텐츠로 제한됨 콘텐츠로 제한됨
DockPanel 제한됨 제한됨
StackPanel(세로 방향) 제한됨 콘텐츠로 제한됨
StackPanel(가로 방향) 콘텐츠로 제한됨 제한됨
Grid 제한됨 제한됨, Auto가 행 및 열에 적용되는 경우에는 예외
WrapPanel 콘텐츠로 제한됨 콘텐츠로 제한됨

이러한 각 요소에 대한 자세한 설명과 사용법 예제는 아래 내용을 참조하세요.

캔버스

Canvas 요소를 통해 절대 x-y- 좌표를 기준으로 콘텐츠를 배치할 수 있습니다. 요소를 고유한 위치에 그릴 수 있고, 여러 요소가 같은 좌표를 사용하는 경우에는 요소가 태그에 표시되는 순서에 따라 요소를 그리는 순서가 결정됩니다.

CanvasPanel의 가장 유연한 레이아웃 지원을 제공합니다. Height 및 Width 속성은 캔버스 영역을 정의하는 데 사용되고 내부 요소에는 부모 Canvas 영역을 기준으로 절대 좌표가 할당됩니다. 네 가지 연결된 속성인 Canvas.Left, Canvas.Top, Canvas.RightCanvas.Bottom을 사용하여 Canvas 내에서 개체 배치를 세밀하게 제어할 수 있으므로 개발자가 화면에서 요소를 세밀하게 배치하고 정렬할 수 있습니다.

캔버스 내의 ClipToBounds

Canvas는 자체 정의된 HeightWidth를 벗어난 좌표를 포함하여 화면의 모든 위치에 자식 요소를 배치할 수 있습니다. 또한 Canvas는 자식 크기의 영향을 받지 않습니다. 따라서 자식 요소가 부모 Canvas의 경계 사각형 외부에 다른 요소를 overdraw할 수 있습니다. Canvas의 기본 동작은 부모 Canvas의 경계 외부에 자식을 그릴 수 있도록 하는 것입니다. 이 동작이 적절하지 않으면 ClipToBounds 속성을 true로 설정할 수 있습니다. 그러면 Canvas가 자체 크기에 맞게 잘립니다. Canvas는 경계 외부에 자식을 그릴 수 있는 유일한 레이아웃 요소입니다.

너비 속성 비교 샘플에서 동작을 그래픽 방식으로 설명합니다.

Canvas 정의 및 사용

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


// 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 ();

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
<Page WindowTitle="Canvas Sample" xmlns="http://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 요소는 컨테이너의 가장자리를 따라 콘텐츠를 배치하도록 자식 콘텐츠 요소에서 설정된 대로 DockPanel.Dock 연결된 속성을 사용합니다. DockPanel.DockTop 또는 Bottom으로 설정되면 자식 요소는 서로의 위 또는 아래에 배치됩니다. DockPanel.DockLeft 또는 Right로 설정되면 자식 요소는 서로의 왼쪽 또는 오른쪽에 배치됩니다. LastChildFill 속성에 따라 DockPanel의 자식으로 추가된 최종 요소의 위치가 결정됩니다.

DockPanel을 사용하여 단추 세트와 같은 관련 컨트롤 그룹을 배치하거나 Microsoft Outlook에 있는 UI처럼 "이동된" UI를 만드는 데 사용할 수 있습니다.

콘텐츠에 맞게 크기 조정

HeightWidth 속성을 지정하지 않으면 DockPanel 크기가 콘텐츠에 맞게 조정됩니다. 자식 요소의 크기를 수용하도록 크기가 증가 또는 감소할 수 있습니다. 하지만 이러한 속성을 지정하고, 지정된 다음 자식 요소에 사용할 공간이 없으면 DockPanel은 이 자식 요소나 후속 자식 요소를 표시하지 않고 후속 자식 요소를 측정하지 않습니다.

LastChildFill

기본적으로 DockPanel 요소의 마지막 자식이 나머지 할당되지 않은 공간을 "채웁니다". 이 동작이 적절하지 않으면 LastChildFill 속성을 false로 설정합니다.

DockPanel 정의 및 사용

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


// Create the application's main window
mainWindow = gcnew Window();
mainWindow->Title = "DockPanel Sample";

// Create the DockPanel
DockPanel^ myDockPanel = gcnew DockPanel();
myDockPanel->LastChildFill = true;

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

Border^ myBorder2 = gcnew Border();
myBorder2->Height = 25;
myBorder2->Background = Brushes::SkyBlue;
myBorder2->BorderBrush = Brushes::Black;
myBorder2->BorderThickness = Thickness(1);
DockPanel::SetDock(myBorder2, Dock::Top);
TextBlock^ myTextBlock2 = gcnew TextBlock();
myTextBlock2->Foreground = Brushes::Black;
myTextBlock2->Text = "Dock = Top";
myBorder2->Child = myTextBlock2;

Border^ myBorder3 = gcnew Border();
myBorder3->Height = 25;
myBorder3->Background = Brushes::LemonChiffon;
myBorder3->BorderBrush = Brushes::Black;
myBorder3->BorderThickness = Thickness(1);
DockPanel::SetDock(myBorder3, Dock::Bottom);
TextBlock^ myTextBlock3 = gcnew TextBlock();
myTextBlock3->Foreground = Brushes::Black;
myTextBlock3->Text = "Dock = Bottom";
myBorder3->Child = myTextBlock3;

Border^ myBorder4 = gcnew Border();
myBorder4->Width = 200;
myBorder4->Background = Brushes::PaleGreen;
myBorder4->BorderBrush = Brushes::Black;
myBorder4->BorderThickness = Thickness(1);
DockPanel::SetDock(myBorder4, Dock::Left);
TextBlock^ myTextBlock4 = gcnew TextBlock();
myTextBlock4->Foreground = Brushes::Black;
myTextBlock4->Text = "Dock = Left";
myBorder4->Child = myTextBlock4;

Border^ myBorder5 = gcnew Border();
myBorder5->Background = Brushes::White;
myBorder5->BorderBrush = Brushes::Black;
myBorder5->BorderThickness = Thickness(1);
TextBlock^ myTextBlock5 = gcnew 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();


// 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 ();

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
<Page xmlns="http://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 요소 간에 크기 정보를 공유하는 메커니즘을 제공합니다.

Grid는 Table과 어떻게 다를까요?

TableGrid는 일부 공통 기능을 공유하지만 각각 서로 다른 시나리오에 가장 적합합니다. Table은 유동 콘텐츠 내에서 사용하도록 디자인되어 있습니다(유동 콘텐츠에 대한 자세한 내용은 유동 문서 개요 참조). 그리드는 폼 내부에서 사용하는 것이 적합합니다(기본적으로 유동 콘텐츠 외부의 모든 위치). FlowDocument 내에서 Table은 페이지 매김, 열 재배치 및 콘텐츠 선택 같은 유동 콘텐츠 동작을 지원하지만 Grid는 지원하지 않습니다. 반면 Grid는 행 및 열 인덱스를 기준으로 요소를 추가하지만 Table은 추가하지 않는다는 것을 포함하여 여러 가지 이유로 GridFlowDocument 외부에서 사용하는 것이 가장 적합합니다. Grid 요소를 사용하면 자식 콘텐츠를 겹칠 수 있으므로 단일 “셀”에 두 개 이상의 요소가 있을 수 있습니다. Table에서는 계층화를 지원하지 않습니다. Grid의 자식 요소는 "셀" 경계의 영역을 기준으로 절대 위치에 배치할 수 있습니다. Table 이 기능을 지원 하지 않습니다. 마지막으로 GridTable보다 가볍습니다.

열 및 행의 크기 조정 동작

Grid 내에 정의된 열 및 행은 Star 크기 조정을 사용하여 나머지 공간을 비례적으로 배분할 수 있습니다. Star를 행이나 열의 높이 또는 너비로 선택하면 해당 열 또는 행에는 나머지 사용 가능한 공간의 가중치가 적용된 부분이 할당됩니다. 이는 열 또는 행 내의 콘텐츠 크기에 따라 공간을 균등하게 배분하는 Auto와 대조적입니다. XAML(Extensible Application Markup Language)을 사용할 때 이 값은 * 또는 2*로 표현됩니다. 첫 번째 경우에 행 또는 열에는 사용 가능한 공간의 1배가 할당되고, 두 번째 경우에는 2배가 할당됩니다. 공간을 비례 배분하는 이 방법을 StretchHorizontalAlignmentVerticalAlignment 값과 결합하면 화면 공간의 백분율에 따라 레이아웃 공간을 분할할 수 있습니다. Grid 이 방식으로 공간을 배분할 수 있는 유일한 레이아웃 패널 이며

그리드 정의 및 사용

다음 예제에서는 Windows [시작] 메뉴에 제공되는 [실행] 대화 상자의 UI와 비슷한 UI를 빌드하는 방법을 보여줍니다.


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

'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

컴파일된 애플리케이션은 다음과 같은 새로운 UI를 생성합니다.

일반적인 그리드 요소.

StackPanel

StackPanel을 사용하여 할당된 방향으로 요소를 "누적"할 수 있습니다. 기본 누적 방향은 세로 방향입니다. Orientation 속성은 콘텐츠 흐름을 제어하는 데 사용될 수 있습니다.

StackPanel과 DockPanel의 차이점

DockPanel은 자식 요소를 "누적"할 수 있지만 DockPanelStackPanel은 일부 사용 시나리오에서 비슷한 결과를 생성하지 않습니다. 예를 들어 자식 요소의 순서는 DockPanel에 있는 요소의 크기에 영향을 미치지만 StackPanel에는 영향을 미치지 않습니다. 이는 StackPanelPositiveInfinity에서 누적 방향으로 측정하지만 DockPanel은 사용 가능한 크기만 측정하기 때문입니다.

다음 예제에서는 이 키의 차이를 보여 줍니다.


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

// Add root Grid
myGrid = gcnew Grid();
myGrid->Width = 175;
myGrid->Height = 150;
RowDefinition^ myRowDef1 = gcnew RowDefinition();
RowDefinition^ myRowDef2 = gcnew RowDefinition();
myGrid->RowDefinitions->Add(myRowDef1);
myGrid->RowDefinitions->Add(myRowDef2);

// Define the DockPanel
myDockPanel = gcnew DockPanel();
Grid::SetRow(myDockPanel, 0);

//Define an Image and Source
Image^ myImage = gcnew Image();
BitmapImage^ bi = gcnew BitmapImage();
bi->BeginInit();
bi->UriSource = gcnew System::Uri("smiley_stackpanel.png", UriKind::Relative);
bi->EndInit();
myImage->Source = bi;

Image^ myImage2 = gcnew Image();
BitmapImage^ bi2 = gcnew BitmapImage();
bi2->BeginInit();
bi2->UriSource = gcnew System::Uri("smiley_stackpanel.png", UriKind::Relative);
bi2->EndInit();
myImage2->Source = bi2;

Image^ myImage3 = gcnew Image();
BitmapImage^ bi3 = gcnew BitmapImage();
bi3->BeginInit();
bi3->UriSource = gcnew System::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 = gcnew StackPanel();
myStackPanel->Orientation = Orientation::Horizontal;
Grid::SetRow(myStackPanel, 1);

Image^ myImage4 = gcnew Image();
BitmapImage^ bi4 = gcnew BitmapImage();
bi4->BeginInit();
bi4->UriSource = gcnew System::Uri("smiley_stackpanel.png", UriKind::Relative);
bi4->EndInit();
myImage4->Source = bi4;

Image^ myImage5 = gcnew Image();
BitmapImage^ bi5 = gcnew BitmapImage();
bi5->BeginInit();
bi5->UriSource = gcnew System::Uri("smiley_stackpanel.png", UriKind::Relative);
bi5->EndInit();
myImage5->Source = bi5;

Image^ myImage6 = gcnew Image();
BitmapImage^ bi6 = gcnew BitmapImage();
bi6->BeginInit();
bi6->UriSource = gcnew System::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();


// 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 ();


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

<Page xmlns="http://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 vs. DockPanel 스크린샷

StackPanel 정의 및 사용

다음 예제에서는 StackPanel을 사용하여 세로로 배치된 단추 세트를 만드는 방법을 보여줍니다. 가로 위치 지정의 경우 Orientation 속성을 Horizontal로 설정합니다.


// 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 ();

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

컴파일된 애플리케이션은 다음과 같은 새로운 UI를 생성합니다.

일반적인 StackPanel 요소.

VirtualizingStackPanel

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

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

다음 태그는 VirtualizingStackPanel을 항목 호스트로 사용하는 방법을 보여줍니다. 가상화를 수행하려면 VirtualizingStackPanel.IsVirtualizingProperty 연결된 속성을 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(사용자 인터페이스) 시나리오에 유용합니다. 또한 모든 자식 요소에 균일한 크기를 적용하는 데 사용될 수 있습니다.

다음 예제에서는 WrapPanel을 만들어 컨테이너의 가장자리에 도달할 때 줄이 바뀌는 Button 컨트롤을 표시하는 방법을 보여줍니다.


// Create the application's main window
mainWindow = gcnew System::Windows::Window();
mainWindow->Title = "WrapPanel Sample";


// Instantiate a new WrapPanel and set properties
myWrapPanel = gcnew WrapPanel();
myWrapPanel->Background = 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 = gcnew Button();
btn1->Content = "Button 1";
btn2 = gcnew Button();
btn2->Content = "Button 2";
btn3 = gcnew 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();


// 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.Width = 200;
myWrapPanel.HorizontalAlignment = HorizontalAlignment.Left;
myWrapPanel.VerticalAlignment = VerticalAlignment.Top;

// Define 3 button elements. The last three buttons are sized at width
// of 75, so the forth button wraps to the next line.
btn1 = new Button();
btn1.Content = "Button 1";
btn1.Width = 200;
btn2 = new Button();
btn2.Content = "Button 2";
btn2.Width = 75;
btn3 = new Button();
btn3.Content = "Button 3";
btn3.Width = 75;
btn4 = new Button();
btn4.Content = "Button 4";
btn4.Width = 75;

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

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

WindowTitle = "WrapPanel Sample"

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

myWrapPanel.Width = 200
myWrapPanel.HorizontalAlignment = Windows.HorizontalAlignment.Left
myWrapPanel.VerticalAlignment = Windows.VerticalAlignment.Top

' Define 3 button elements. The last three buttons are sized at width 
' of 75, so the forth button wraps to the next line.
Dim btn1 As New Button()
btn1.Content = "Button 1"
btn1.Width = 200
Dim btn2 As New Button()
btn2.Content = "Button 2"
btn2.Width = 75
Dim btn3 As New Button()
btn3.Content = "Button 3"
btn3.Width = 75
Dim btn4 As New Button()
btn4.Content = "Button 4"
btn4.Width = 75

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

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

<Page xmlns="http://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 요소는 서로의 내부에 중첩되어 복잡한 레이아웃을 생성할 수 있습니다. 이 방법은 하나의 Panel이 UI의 한 부분에는 적합하지만 UI의 다른 부분에 대한 요구 사항을 충족할 수 없는 상황에서 매우 유용합니다.

애플리케이션에서 지원할 수 있는 중첩 횟수에는 실제로 제한이 없지만, 일반적으로 원하는 레이아웃에 실제로 필요한 패널만 사용하도록 애플리케이션을 제한하는 것이 가장 좋습니다. 대부분의 경우 Grid 요소는 레이아웃 컨테이너로서의 유연성 때문에 중첩 패널 대신 사용될 수 있습니다. 이 요소를 통해 불필요한 요소를 트리에서 제거하여 애플리케이션 성능을 향상할 수 있습니다.

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


// 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);
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)

컴파일된 애플리케이션은 다음과 같은 새로운 UI를 생성합니다.

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

사용자 지정 Panel 요소

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

마찬가지로 파생 클래스(예: Canvas 또는 Grid)를 기반으로 한 사용자 지정 레이아웃 동작을 정의하려면 ArrangeOverrideMeasureOverride 메서드를 재정의합니다.

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

public: 
   ref class PlotPanel : Panel {

   public: 
      PlotPanel () {};

   protected: 
      // Override the default Measure method of Panel
      virtual Size MeasureOverride(Size availableSize) override
      {
          Size^ panelDesiredSize = gcnew Size();

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

   protected: 
      virtual System::Windows::Size ArrangeOverride (Size finalSize) override 
      {
         for each (UIElement^ child in InternalChildren)
         {
            double x = 50;
            double y = 50;
            child->Arrange(Rect(Point(x, y), child->DesiredSize));
         }
         return finalSize;
      };
   };
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
    }
}
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 panelDesiredSize As Size = New Size()
        ' In our example, we just have one child. 
        ' Report that our panel requires just the size of its only child.
        For Each child As UIElement In InternalChildren
            child.Measure(availableSize)
            panelDesiredSize = child.DesiredSize
        Next
        Return panelDesiredSize
    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 finalSize
    End Function
End Class

더 복잡한 사용자 지정 패널 구현을 보려면 Create a Custom Content-Wrapping Panel Sample(사용자 지정 콘텐츠 줄 바꿈 패널 샘플 만들기)을 참조하세요.

지역화/세계화 지원

WPF는 지역화 가능한 UI를 만들기에 유용한 다양한 기능을 지원합니다.

모든 패널 요소는 기본적으로 사용자의 로캘 또는 언어 설정에 따라 콘텐츠를 동적으로 재배치하는 데 사용할 수 있는 FlowDirection 속성을 지원합니다. 자세한 내용은 FlowDirection를 참조하세요.

SizeToContent 속성은 애플리케이션 개발자가 지역화된 UI의 요구 사항을 예상할 수 있는 메커니즘을 제공합니다. 이 속성의 WidthAndHeight 값을 사용하면 부모 Window는 항상 콘텐츠에 맞게 동적으로 크기가 조정되고 인위적인 높이 또는 너비 제한이 적용되지 않습니다.

DockPanel, GridStackPanel은 모두 지역화 가능한 UI에 적절한 선택입니다. Canvas는 콘텐츠를 절대적으로 배치해서 지역화하기 어렵기 때문에 적절한 선택이 아닙니다.

지역화 가능한 UI(사용자 인터페이스)가 포함된 WPF 애플리케이션을 만드는 방법에 대한 자세한 내용은 자동 레이아웃 사용 개요를 참조하세요.

참고 항목