XAML은 현재 총 3편의 시리즈로 구성되어 있습니다.
- 헬로 XAML #1
- 헬로 XAML #2 (현재글)
- 헬로 XAML #3
들어가며
저번 글에 이어서 이번 글에서는 HTML의 태그와 비슷한 XAML의 컨트롤들을 알아봅시다. 그중에 레이아웃 요소들을 결정하는 컨트롤에 대해 알아보겠습니다.
XAML 레이아웃 컨트롤

HTML로 위와 같은 레이아웃을 잡을 때 보통 어떻게 코드를 작성하시나요?
저라면 목록을 나타내는 ul 태그에 display flex 속성을 사용해서 작업할 것 같은데요, ul 태그는 블록 요소라서 자식들이 수직으로 쌓이게 되지만 css의 display flex 속성을 통해서 바꿀 수 있었죠. 하지만 xaml에서는 동일한 레이아웃을 잡을 때 컨트롤을 사용하게 됩니다.
쉽게 말하면 html에서는 블록 요소, 인라인 요소의 구조를 바꾸려면 css로 변경하면 되지만 xaml의 개념을 적용하면 구조를 결정할 때 태그 자체로 결정되기 때문에 알맞은 컨트롤을 사용하는 게 중요합니다.
여기까지 보고 무슨 소리지 라고 생각하시는 분들이 많을 것 같은데요,
저도 처음에는 이런 개념이 기존에 작업하던 웹 방식이랑 비슷해보이지만 많이 달라서 어려웠습니다.
제일 빨리 이해하는 방법은 직접 해보는 게 최고거든요!
같이 따라 해보면서 레이아웃을 결정하는 컨트롤들을 알아봅시다.
Grid
프로젝트를 하면서 제일 많이 사용한 Grid 컨트롤입니다. 그만큼 가장 중요하다고 할 수 있죠.
Grid는 HTML처럼 블록 요소를 연속으로 사용하면 쌓인다는 개념이 아니고 사용하는 영역을 나눠서 정해주는 컨트롤입니다.
[Grid의 영역을 나눠주는 속성]
- Grid.ColumnDefinitions → 행 그룹 지정
- ColumnDefinition → 행 개수 지정 (table th, td 느낌)
- Grid.RowDefinitions → 열 그룹 지정
- RowDefintions → 열 개수 지정 (table tr 느낌)
[Grid의 영역을 지정해주는 속성]
- Grid.Row → 열 위치 지정 (default: 0)
- Grid.Column → 행 위치 지정 (default: 0)
일단 직접 만들어볼까요?
저번에 만든 MainWindow.xaml에 Grid를 만들어보겠습니다.
디자인 모드를 보면 흰 도화지에 아무것도 표현되지 않았네요.
행을 결정하는 ColumnDefinions 속성의 ColumnDefinition을 2번 사용해서 2개의 영역으로 나눠보겠습니다.

여기까지 따라오셨나요? 디자인 모드로 확인해보면 2개의 영역으로 나뉘었습니다!
마찬가지로 열을 결정하는 RowDefintions의 RowDefinition을 2번 사용해서 2개의 영역을 나눠보겠습니다.


디자인 모드에서 이렇게 총 4개의 영역이 만들어지셨나요? 그러면 완벽합니다.
이제 우리가 만든 영역에 버튼, 텍스트 같은 컨트롤들을 배치할 수 있게 되었습니다!
그러면 영역에 배치를 해볼까요? 위 4개 영역을 시계방향 순으로 순서를 매긴다면 2번 위치에 TextBlock이라는 텍스트를 표시하는 컨트롤을 배치해봅시다.


무슨 뜻이냐면 Grid로 영역을 나누면 아래 그림처럼 영역별로 순서대로 0부터 시작하는 고유번호가 있다고 생각하면 됩니다.


그렇다면 우리가 원하는 2번에 위치하려면 어떻게 하면 될까요? Grid.Column=”1”, Grid.Row=”0” 으로 지정해주면 됩니다. (여기서 0은 기본값이기 때문에 값이 0인 경우 쓰는 걸 생략해도 됩니다.)

텍스트가 2번 영역에 배치되었습니다!
이렇게 배치된 컨트롤들은 기본적으로 width, height 또는 정렬(HorizontalAlignment, VerticalAlignment)을 지정해주지 않으면 꽉 차게 들어갑니다.

이렇듯 Grid는 영역을 나눠서 Grid.Row, Grid.Column을 통해서 각자의 영역에 배치될 수 있게 하는 컨트롤입니다.
보통 헤더, 컨텐츠, 푸터 이렇게 큰 레이아웃을 나눌 때도 사용되고 일반적인 컨트롤 요소에도 많이 사용됩니다. 그래서 이 Grid 컨트롤 개념을 정확히 이해하는 게 중요합니다.
StackPanel
그렇다면 HTML의 블록 요소 같은 레이아웃은 아예 없을까요? 노노 StackPanel이라는 컨트롤이 있습니다.
수직, 수평을 결정해주는 Orientation 속성을 사용해서 컨트롤을 쌓을 수 있습니다.
[Orientation 속성]
- Vertical → 수직 (default)
- Horizontal → 수평
위에서 나눈 영역 중 3번 영역에 StackPanel을 만들어볼까요? 기본적으로 Vertical이 기본값입니다.

3번 영역에 1, 2, 3이 차례로 쌓인걸 볼 수 있습니다.
Orientation 속성을 Horizontal로 바꿔볼까요?


수평으로 잘 쌓이는걸 볼 수 있습니다!
Border
Border라는 이름에서 주는 느낌이 있죠? 맞습니다, 바로 선입니다.
XAML은 선이 있는 박스를 Border라는 컨트롤을 사용해야 만들 수 있습니다.
HTML에서 모든 태그 css의 border 속성으로 선을 줄 수 있었다면 XAML은 컨트롤(태그)을 사용해서 만들 수 있다는 것이죠. (여간 불편한 게 아닙니다.)
(※ 다만 대부분 border 효과를 줄 수 없지만, 도형요소(Ellipse, Rectangle)는 stroke을 통해 border효과를 줄 수 있습니다.)
또 특별한 특성 중에 하나는 2개 이상의 자식 요소를 가질 수 없습니다.
[Border 컨트롤 속성]
- BorderThickness → 선의 두께를 결정합니다.
- BorderBrush → 선의 색상을 결정합니다.
- CornerRadius → 선의 라운딩을 결정합니다.
계속해서 1번 영역에 Border 박스를 그려봅시다.

노란색 박스가 잘 그려졌네요! 아래처럼 자식 요소를 2번 쓰게 되면 에러가 나면서 줄이 그어지게 됩니다. 그래서 보통 작업할 때 선이 있다면 Border 컨트롤안에 Grid나 StacKPanel처럼 다른 레이아웃 컨트롤을 넣어서 사용합니다.

Canvas
CSS의 position absolute 속성이 태그로 나왔다고 생각하면 좋을 것 같습니다.
Grid는 행렬로 영역을 나눴다면 Canvas는 영역 안에서 좌표로 영역을 설정할 수 있습니다.
[Canvas 좌표를 지정하는 속성]
- Canvas.Left → 왼쪽에서부터
- Canvas.Right → 오른쪽에서부터
- Canvas.Top → 위쪽에서부터
- Canvas.Bottom → 아래쪽에서부터
4번 영역의 Button을 지우고 Canvas를 넣어봅시다.


왼쪽에서 20 위쪽에서 100만큼 떨어진 hyejun을 볼 수 있습니다! Canvas는 애니메이션 작업을 할 때 많이 썼는데요, 좌표를 설정할 수 있어서 디자인 위치가 자유로운 애니메이션 작업에 적합했었습니다.
WrapPanel
WrapPanel은 StackPanel과 유사하지만 StackPanel은 자식 요소가 부모 요소의 영역을 넘어가면 그냥 넘쳐서 넘어가 버립니다. 하지만 WrapPanel은 넘어가지 않게 줄 바꿈을 자동으로 해주죠.
[Orientation 속성]
- Vertical → 수직 (default)
- Horizontal → 수평
아까의 StackPanel에 TextBlock을 엄청 많이 넣어볼까요?

줄 바꿈이 된 모습을 볼 수 있습니다.
일단 여기까지 레이아웃을 결정하는 컨트롤들을 알아보았습니다.
위에서 언급한 레이아웃 컨트롤말고 더 있지만 작업할 때는 설명한 레이아웃으로 대부분 작업을 했기 때문에 여기까지 알아보도록 하고, 더 많은 레이아웃 컨트롤을 보고 싶으시면 아래 경로를 참고해주세요.
https://docs.microsoft.com/ko-kr/windows/apps/design/layout/layouts-with-xaml
마치며
제가 XAML을 작업하면서 가장 어렵고 까다롭게 여긴게 레이아웃 개념이라서,
더 쉽고 자세하게 설명하고 싶었는데 이해가 잘 가셨을지 모르겠네요.
다음 시간에는 레이아웃 컨트롤 안에 들어가는 일반 컨트롤들을 한 번 알아보겠습니다.
긴~글 읽어주셔서 감사합니다. 😄