WPF Layout (Panels)

김정환(John.Kim)
OldbeeDev
Published in
11 min readSep 10, 2017
©200degrees (pixabay)

Window는 컨텐츠용 차일드를 하나만 포함할 수 있다. 다행히 WPF에서는 여러 개의 차일드를 적절히 배치해주는 Panel 계열 클래스를 제공하기 때문에 Panel 객체를 Window의 차일드로 사용함으로써 다양한 화면 구성을 할 수 있다.

이번 글에서는 Panel 클래스 중에서 Canvas, StackPanel, WrapPanel, Grid에 대해 설명한다.

Canvas

Canvas는 Canvas.Left, Canvas.Top 속성의 좌표 값에 따라 차일드 컨트롤을 배치한다. 이들 속성은 각각 Canvas 영역의 왼쪽, 위쪽 경계부터의 거리이다. 차일드 컨트롤의 크기는 Width, Height 속성의 숫자 값에 따라 표시된다.

<Canvas>
<Button Canvas.Left=”0" Canvas.Top=”0"
Width=”100" Height=”100" Background=”Red” Content=”RED”/>
<Button Canvas.Left=”100" Canvas.Top=”100"
Width=”100" Height=”100" Background=”Green” Content=”GREEN”/>
<Button Canvas.Left=”50" Canvas.Top=”50"
Width=”100" Height=”100" Background=”Yellow” Content=”YELLOW”/>
</Canvas>

실행 화면은 아래와 같다.

Yellow를 마지막에 그렸으므로 Z-Order가 최상이다.

창 크기를 줄여도 Canvas 내부의 버튼 위치나 크기는 영향을 받지 않는다.

스크롤바가 생기게 하는 방법은 다음 기회에…

StackPanel

StackPanel은 차일드 컨트롤을 가로 또는 세로 방향 한 줄로만 나열한다. 방향은 Orientation 속성으로 지정하며 기본값은 Vertical이다. 차일드 컨트롤이 StackPanel의 공간을 벗어나면 화면에 보이지 않는다.

<StackPanel Orientation=”Horizontal”>
<TextBlock VerticalAlignment=”Center” FontSize=”20"
Text=”Circles : “ />
<Ellipse Width=”100" Height=”100" Margin=”4,0,0,0" Fill=”Red”/>
<Ellipse Width=”80" Height=”80" Margin=”4,0,0,0" Fill=”Orange”/>
<Ellipse Width=”60" Height=”60" Margin=”4,0,0,0" Fill=”Yellow”/>
<Ellipse Width=”40" Height=”40" Margin=”4,0,0,0" Fill=”Green”/>
<Ellipse Width=”20" Height=”20" Margin=”4,0,0,0" Fill=”Blue”/>
</StackPanel>

실행 화면은 아래와 같다.

TextBlock에 VerticalAlignment를 주지 않으면 Top에 붙어보인다.

WrapPanel

WrapPanel은 가로 및 세로 방향으로 차일드 컨트롤을 나열하긴 하지만, Orientaion 속성의 기본값이 Horizontal이고, WrapPanel의 공간이 부족할 경우 자동 줄바꿈을 수행한다. 또한 차일드 컨트롤의 크기를 임의로 변경시키는 특징도 있는데 그 규칙은 다음과 같다.

  • 가로 방향 : 같은 가로줄의 모든 차일드는 그 줄의 최대 높이에 맞춰진다.
  • 세로 방향 : 같은 세로줄의 모든 차일드는 그 줄의 최대 너비에 맞춰진다.
<WrapPanel >
<Button>Test button 1</Button>
<Button>Test button 2</Button>
<Button>Test button 3</Button>
<Button Height=”40">Test button 4</Button>
<Button>Test button 5</Button>
<Button>Test button 6</Button>
</WrapPanel>

너비 공간이 충분할 때는 모든 버튼이 높이 40 px이다.

Button5에서 줄바꿈이 되면 첫번째 줄만 높이 40 px이 된다.

Ugly하다.

Button4에서 줄바꿈이 되면 두번째 줄만 높이 40 px이 된다.

역시 Ugly하다.

만약 줄바꿈이 되더라도 모든 차일드 컨트롤이 같은 크기가 되기를 원한다면 WrapPanel의 ItemWidth, ItemHeight 속성을 지정한다.

<WrapPanel ItemHeight=”40">
<Button>Test button 1</Button>
<Button>Test button 2</Button>
<Button>Test button 3</Button>
<Button>Test button 4</Button>
<Button>Test button 5</Button>
<Button>Test button 6</Button>
</WrapPanel>

실행 화면은 아래와 같다.

ItemHeight, ItemWidth는 필수여야 하겠다.

Grid

Grid는 테이블 형태의 레이아웃을 제공하는 클래스로서 사용 빈도가 매우 높은 클래스 중 하나이다. Grid.RowDefinitions, Grid.ColumnDefinitions를 통해 Row와 Column을 생성하고 그렇게 생성된 각각의 Cell에 차일드 컨트롤을 추가한다. Cell에는 일반적인 컨트롤 뿐만 아니라 또 다른 Panel 객체도 추가할 수 있다. 연속된 Cell 공간을 하나의 차일드로 병합하는 기능도 제공한다.

아래는 2 Rows, 3 Columns인 등간격 Grid의 예이다.

<Grid ShowGridLines=”True” Margin=”5">
<Grid.RowDefinitions>
<RowDefinition/>
<RowDefinition/>
</Grid.RowDefinitions>
<Grid.ColumnDefinitions>
<ColumnDefinition/>
<ColumnDefinition/>
<ColumnDefinition/>
</Grid.ColumnDefinitions>
<TextBlock Text=”Row0 Column0" Grid.Row=”0" Grid.Column=”0"/>
<TextBlock Text=”Row0 Column1" Grid.Row=”0" Grid.Column=”1"/>
<TextBlock Text=”Row0 Column2" Grid.Row=”0" Grid.Column=”2"/>
<TextBlock Text=”Row1 Column0" Grid.Row=”1" Grid.Column=”0"/>
<Button Content=”Row1 Column1" Grid.Row=”1" Grid.Column=”1"/>
<Button Content=”Row1 Column2" Grid.Row=”1" Grid.Column=”2"/>
</Grid>

실행 화면은 아래와 같다.

GridLines는 Cell 영역을 보여주기 위한 디버깅 용도.

Grid Cell의 크기는 RowDefinition.Height, ColumnDefinition.Width 속성에 입력한 값에 따라 3가지 방식으로 표현할 수 있다.

  • Fixed Sizing : pixel 단위 값 (1 inch = 96 px)
  • Star Sizing : “1*”, “2*” 등의 상대 비율로 입력한다.
  • Auto Sizing : “AUTO”라고 입력하면 각 Cell에 위치한 차일드 컨트롤의 크기에 따라 자동으로 Cell 크기가 정해진다.
<Grid Margin=”5" ShowGridLines=”True”>
<Grid.RowDefinitions>
<RowDefinition Height=”3*” />
<RowDefinition Height=”1*” />
<RowDefinition Height=”AUTO” />
</Grid.RowDefinitions>
<Grid.ColumnDefinitions>
<ColumnDefinition Width=”*” />
<ColumnDefinition Width=”AUTO” />
<ColumnDefinition Width=”100" />
</Grid.ColumnDefinitions>
<Label Grid.ColumnSpan=”3"
HorizontalAlignment=”Stretch”
VerticalAlignment=”Stretch”
HorizontalContentAlignment=”Center”
VerticalContentAlignment=”Center”
Background=”AliceBlue”
FontSize=”30"
Content=”Merged Area” />
<Label Grid.Row=”1" Content=”Row1" />
<Label Grid.Row=”2" Grid.Column=”0" Content=”Row2" />
<Button Grid.Row=”2" Grid.Column=”1" Width=”150" Height=”35"
Content=”Wide Button” />
<Button Grid.Row=”2" Grid.Column=”2" Height=”25"
VerticalAlignment=”Bottom” Content=”Button” />
</Grid>

실행 화면은 아래와 같다. 첫번째 줄은 ColumnSpan을 사용하여 한 Cell로 병합되었고 첫번째 줄과 두번째 줄의 높이는 3:1 비율이다. 세번째 줄의 높이는 Wide Button의 높이에 따라 35 px이 되었고, Button의 높이는 25 px이기 때문에 버튼 위에 여백이 생겼다.

설명을 위한 의미없는 예제

Wrapup :

Canvas에 StackPanel이 들어가고, StackPanel에 Grid가 들어가고, Grid에 Grid가 들어가고, Grid에 StackPanel이 들어가고, … , 뭐든지 만들 수 있다.
물론 초반 삽질은 피할 수 없다. 😈

References :

--

--