3.2 XAML - Panels
01. Panel 개요
*Grid (격자) 만 이해하고, 나머지는 필요한 경우에 다시 확인합니다.
- 컨트롤은 WPF 에서 사용하는 버튼, 레이블과 같은 UI 객체를 의미합니다
- 컨테이너는 프로그래밍에서 일반적으로 무엇인가를 담을 수 있는 공간을 의미하는 단어 입니다.
WPF와 같은 UI 디자인 툴에서 컨테이너는, 컨트롤 여러개를 한번에 담아 관리할 수 있는 객체를 의미합니다. - 레이아웃은 일반적으로 배치라는 뜻을 가지고 있습니다.
WPF와 같은 UI 디자인 툴에서 레이아웃은, 개별 컨트롤의 위치를 관리하는 기능을 의미합니다.
Panel은 WPF 컨트롤 중 Canvas, StackPane, Grid와 같은 컨트롤을 지칭하는 용어입니다.
Panel의 기능은, 버튼, 레이블, 텍스트 박스 등의 기본 컨트롤 여러개를 담는 컨테이너 역할을 합니다.
Panel은 담겨진 여러 기본 컨트롤들의 위치를 조정하는 레이아웃 관리 기능이 있습니다.
그래서 windows/page와 개별 컨트롤들 사이에서 컨트롤의 위치를 적절히 배치하여 제어할 수 있습니다.
WPF 기본 템플릿으로 생성한 프로젝트를 실행하면, 하나의 Windows 창을 확인할 수 있습니다.
panel을 여러 컨트롤을 담는 컨테이너로 구조로 사용하고, 레이아웃을 관리하게 하고 Windows 하위 컨트롤로 사용합니다.
Panel들은 내부에 사용할 레이아웃과 자식 컨트롤들에 따라 여러가지 다른 형태로 되어있습니다.
원하는 형태와 동작을 가지는 적절한 panel을 선택해야 하는 일은 어려운 일 일수 있습니다.
그럼에도 Panel 을 다른 기본 컨트롤 보다 먼저 소개하는 이유는, 여러분들은 기본적으로 버튼이나 레이블과 같은 UI 객체들을 다뤄본 경험이 있기 때문에 필요한 컨트롤은 그때그때 찾아서 사용하시면 됩니다.
02. Canvas
WinForms 방식을 모방한 가장 간단한 구조의 패널입니다.
Canvas Panel에 담긴 각 자식 컨트롤의 특정 좌표를 할당하여 레이아웃을 완벽하게 제어합니다.
Canvas Panel에 포함된 자식 컨트롤을 수동으로 지정하고 정렬해야 하기 때문에 유연성이 매우 떨어집니다.
Panel에 담긴 각 컨트롤의 위치를 완전히 제어하려는 경우에 사용합니다.
02.1 Canvas Panel의 기본 동작 구조
<Canvas Panel>에 <Button> 컨트롤 3개를 추가했지만, 동일한 위치에 놓여 있으므로 마지막 버튼만 보입니다.
<Canvas Panel>은 자식 컨트롤에 좌표를 제공하기 전까지는 아무 것도하지 않습니다.
기본적으로 좌표는 모두 NaN (Not a Number)으로 설정되고, 기본값은 Canvas를 왼쪽 위 모서리에 위치합니다.
<Canvas>
<Button>Button 1</Button>
<Button>Button 2</Button>
<Button>Button 3</Button>
</Canvas>
02.2 Canvas Panel 사용법
<Canvas Panel>은 네 모서리를 기준으로 Left, Right, Top 및 Bottom 속성을 사용하여 좌표를 줄 수 있습니다.
첫번째 버튼은 Left 기준으로, 두번째 버튼은 Right 기준으로 X축 값을 지정했습니다.
세번재 버튼은 좌하단(Left, Bottom) 기준으로, 네번째 버튼은 우하당(Right, Button) 기준으로 X축 값을 지정했습니다.
모두 X축에 할당한 값의 방향은 프로그램 내부로 향합니다.
<Canvas>
<Button Canvas.Left="10">Top left</Button>
<Button Canvas.Right="10">Top right</Button>
<Button Canvas.Left="10" Canvas.Bottom="10">Bottom left</Button>
<Button Canvas.Right="10" Canvas.Bottom="10">Bottom right</Button>
</Canvas>
02.3 Z-Index
일반적으로 Canvas 내의 컨트롤이 겹치면 마지막으로 정의된 컨트롤이, 마지막에 그려지기 때문에 가장 위에 표시됩니다.
그러나 Panel 클래스에 연결된 ZIndex 속성을 사용하면 이 순서를 쉽게 변경할 수 있습니다.
높은 z-index를 가진 컨트롤은 낮은 값을 가진 컨트롤 위에 올라옵니다.
z-index의 값이 동일하면 나중에 정의된 컨트롤이 위로 올라옵니다.
<Canvas>
<Ellipse Panel.ZIndex="1" Fill="Gainsboro" Canvas.Left="25" Canvas.Top="25" Width="200" Height="200" />
<Rectangle Panel.ZIndex="4" Fill="LightBlue" Canvas.Left="25" Canvas.Top="25" Width="50" Height="50" />
<Rectangle Panel.ZIndex="3" Fill="LightCoral" Canvas.Left="50" Canvas.Top="50" Width="50" Height="50" />
<Rectangle Panel.ZIndex="2" Fill="LightCyan" Canvas.Left="75" Canvas.Top="75" Width="50" Height="50" />
</Canvas>
03. WrapPanel
WrapPanel은 더 이상 공간이 없을 때까지 각 자식 컨트롤을 가로 또는 세로로 배치하고, Windows에 공간이 없을 때 자동으로 줄바꿈하여 배치됩니다.
WrapPanel에서 Horizontal orientation(가로 방향)은 하위 컨트롤에 가장 높은 항목을 기준으로 동일한 높이가 지정됩니다.
WrapPanel에서 Vertical orientation(세로 방향)이면 자식 컨트롤에 가장 넓은 항목을 기준으로 동일한 너비가 지정됩니다.
03.1 Horizontal orientation
가로 방향은, 높이가 가장 큰 값을 기준으로 동일하게 지정됩니다.
네번째 버튼의 높이를 기준으로 설정되었습니다.
<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>
03.2 Vertical orientation
세로 방향은, 넓이가 가장 큰 값을 기준으로 동일하게 지정됩니다.
네번째 버튼의 넓이를 기준으로 설정되었습니다.
<WrapPanel Orientation="Vertical">
<Button>Test button 1</Button>
<Button>Test button 2</Button>
<Button>Test button 3</Button>
<Button Width="160">Test button 4</Button>
<Button>Test button 5</Button>
<Button>Test button 6</Button>
</WrapPanel>
03.3 추가
WrapPanel은 가로 방향은, 높이가 가장 큰 값을 기준으로 동일하게 지정됩니다. (Button 4,5,6)
하지만, 넓이는 다를 수 있습니다. (Button 1,2,3 vs Button 4,5,6)
반대로 WrapPanel은 세로 방향은, 넓이가 가장 큰 값을 기준으로 동일하게 지정됩니다. (Button 4,5)
하지만, 높이는 다를 수 있습니다. (Button 1,2,3 vs Button 4,5)
04. StackPanel
StackPanel은 WrapPanel과 마찬가지로 방향은 가로/세로 둘다 가능하지만,
가장 큰 항목을 기준으로 하위 컨트롤의 너비와 높이를 함께 조정합니다.
04.1 기본 구조
중요 차이점은, 패널에 추가된 하위 컨트롤들이 사용 가능한 공간을 넘어서면, 배치 방향으로 패널 확장합니다.
윈도우의 크기는 고정되어 있으니 보여지는 패널의 크기는 잘려나갑니다.
요약하자면, StackPanel은 콘텐츠를 배치할 충분한 공간이 있는지를 신경 쓰지 않습니다.
<StackPanel>
<Button>Button 1</Button>
<Button>Button 2</Button>
<Button>Button 3</Button>
<Button>Button 4</Button>
<Button>Button 5</Button>
<Button>Button 6</Button>
</StackPanel>
<StackPanel Orientation="Horizontal">
<Button>Button 1</Button>
<Button>Button 2</Button>
<Button>Button 3</Button>
<Button>Button 4</Button>
<Button>Button 5</Button>
<Button>Button 6</Button>
</StackPanel>
04.2 Stretch 속성 제거
StackPanel은 기본적으로 자식 컨트롤을 확장합다.
세로(vertical)로 정렬된 StackPanel에서 모든 자식 컨트롤은 가로로 늘어납니다.
가로(horizontal)로 정렬된 StackPanel에서 모든 하위 컨트롤이 세로로 늘어납니다.
StackPanel은 자식 컨트롤의 HorizontalAlignment 또는 VerticalAlignment 속성을 Stretch로 설정하여 이 작업을 수행하지만 원하는 경우 쉽게 재정의 할 수 있습니다.
모든 하위 컨트롤의 VerticalAlignment 속성에 값을 Top, Center 및 Bottom 을 사용하여 버튼을 배치합니다.
<StackPanel Orientation="Horizontal">
<Button VerticalAlignment="Top">Button 1</Button>
<Button VerticalAlignment="Center">Button 2</Button>
<Button VerticalAlignment="Bottom">Button 3</Button>
<Button VerticalAlignment="Bottom">Button 4</Button>
<Button VerticalAlignment="Center">Button 5</Button>
<Button VerticalAlignment="Top">Button 6</Button>
</StackPanel>
<StackPanel Orientation="Vertical">
<Button HorizontalAlignment="Left">Button 1</Button>
<Button HorizontalAlignment="Center">Button 2</Button>
<Button HorizontalAlignment="Right">Button 3</Button>
<Button HorizontalAlignment="Right">Button 4</Button>
<Button HorizontalAlignment="Center">Button 5</Button>
<Button HorizontalAlignment="Left">Button 6</Button>
</StackPanel>
05. DockPanel
DockPanel을 사용하면 하위 컨트롤을 위, 아래, 왼쪽, 오른쪽으로 위치 시킬 수 있습니다.
그리고 기본적으로 마지막 컨트롤은 특정 위치가 지정되지 않은 경우 남아있는 가운데 공간을 채웁니다.
Grid 패널에서도 동일한 결과를 얻을 수 있지만, 보다 단순한 상황에서는 DockPanel을 더 쉽게 사용할 수 있습니다.
05.1 기본 사용법
하위 컨트롤의 우선순위는 왼쪽 > 위 > 오른쪽 > 아래 입니다.
<DockPanel>
<Button DockPanel.Dock="Left">Left</Button>
<Button DockPanel.Dock="Top">Top</Button>
<Button DockPanel.Dock="Right">Right</Button>
<Button DockPanel.Dock="Bottom">Bottom</Button>
<Button>Center</Button>
</DockPanel>
05.2 컨트롤 우선순위 변경
DockPanel.Dock 속성으로 우선순위를 작성하면, 선언된 컨트롤 순서로 배치 우선순위를 가집니다.
<DockPanel>
<Button DockPanel.Dock="Top" Height="50">Top</Button>
<Button DockPanel.Dock="Bottom" Height="50">Bottom</Button>
<Button DockPanel.Dock="Left" Width="50">Left</Button>
<Button DockPanel.Dock="Right" Width="50">Right</Button>
<Button>Center</Button>
</DockPanel>
05.3 우선순위 제거
LastChildFill 속성을 사용하여 DockPanel의 하위 컨트롤 레이아웃 자동 배치 기능을 비활성화 시킬 수 있습니다.
<DockPanel LastChildFill="False">
<Button DockPanel.Dock="Top" Height="50">Top</Button>
<Button DockPanel.Dock="Bottom" Height="50">Bottom</Button>
<Button DockPanel.Dock="Left" Width="50">Left</Button>
<Button DockPanel.Dock="Left" Width="50">Left</Button>
<Button DockPanel.Dock="Right" Width="50">Right</Button>
<Button DockPanel.Dock="Right" Width="50">Right</Button>
</DockPanel>
06. Grid (격자)
Grid는 아마 가장 복잡한 패널이지만, 가장 유용합니다.
Grid에는 여러 행과 열이 포함될 수 있습니다.
각 행의 높이와 각 열의 너비를 픽셀의 절대 크기 또는 사용 가능한 공간의 백분율로, 또는 컨텐츠 크기에 따라 행 또는 열을 자동으로 조정합니다.아래 이미지는 예제입니다.
예제1)
<!--Height="250" Width="220"-->
<Grid Margin="10">
<Grid.ColumnDefinitions>
<ColumnDefinition Width="Auto" />
<ColumnDefinition Width="*" />
</Grid.ColumnDefinitions>
<Grid.RowDefinitions>
<RowDefinition Height="Auto" />
<RowDefinition Height="Auto" />
<RowDefinition Height="*" />
</Grid.RowDefinitions>
<Label>Name:</Label>
<TextBox Grid.Column="1" Margin="0,0,0,10" />
<Label Grid.Row="1">E-mail:</Label>
<TextBox Grid.Row="1" Grid.Column="1" Margin="0,0,0,10" />
<Label Grid.Row="2">Comment:</Label>
<TextBox Grid.Row="2" Grid.Column="1" AcceptsReturn="True" />
</Grid>
예제2)
<!--Height="525" Width="350"-->
<Grid Margin="10">
<Grid.ColumnDefinitions>
<ColumnDefinition Width="*"/>
<ColumnDefinition Width="*"/>
<ColumnDefinition Width="*"/>
<ColumnDefinition Width="*"/>
</Grid.ColumnDefinitions>
<Grid.RowDefinitions>
<RowDefinition Height="2*"/>
<RowDefinition Height="*"/>
<RowDefinition Height="*"/>
<RowDefinition Height="*"/>
<RowDefinition Height="*"/>
<RowDefinition Height="*"/>
</Grid.RowDefinitions>
<Label x:Name="resultLabel"
Content="0"
HorizontalAlignment="Right"
VerticalAlignment="Bottom"
FontSize="60"
Grid.ColumnSpan="4"/>
<Button x:Name="acButton"
Content="AC"
Margin="5"
Grid.Row="1"/>
<Button x:Name="negativeButton"
Content="+/1"
Margin="5"
Grid.Row="1"
Grid.Column="1"/>
<Button x:Name="percentageButton"
Content="%"
Margin="5"
Grid.Row="1"
Grid.Column="2"/>
<Button x:Name="divisionButton"
Content="/"
Margin="5"
Grid.Row="1"
Grid.Column="3"/>
<Button x:Name="sevenButton"
Click="sevenButton_Click"
Content="7"
Margin="5"
Grid.Row="2"/>
<Button x:Name="eightButton"
Content="8"
Margin="5"
Grid.Row="2"
Grid.Column="1"/>
<Button x:Name="nineButton"
Content="9"
Margin="5"
Grid.Row="2"
Grid.Column="2"/>
<Button x:Name="multiplicationButton"
Content="*"
Margin="5"
Grid.Row="2"
Grid.Column="3"/>
<Button x:Name="fourButton"
Content="4"
Margin="5"
Grid.Row="3"/>
<Button x:Name="fiveButton"
Content="5"
Margin="5"
Grid.Row="3"
Grid.Column="1"/>
<Button x:Name="sixButton"
Content="6"
Margin="5"
Grid.Row="3"
Grid.Column="2"/>
<Button x:Name="minusButton"
Content="-"
Margin="5"
Grid.Row="3"
Grid.Column="3"/>
<Button x:Name="oneButton"
Content="1"
Margin="5"
Grid.Row="4"/>
<Button x:Name="twoButton"
Content="2"
Margin="5"
Grid.Row="4"
Grid.Column="1"/>
<Button x:Name="threeButton"
Content="3"
Margin="5"
Grid.Row="4"
Grid.Column="2"/>
<Button x:Name="plusButton"
Content="+"
Margin="5"
Grid.Row="4"
Grid.Column="3"/>
<Button x:Name="zeroButton"
Content="0"
Margin="5"
Grid.Row="5"
Grid.ColumnSpan="2"/>
<Button x:Name="pointButton"
Content="."
Margin="5"
Grid.Row="5"
Grid.Column="2"/>
<Button x:Name="equalButton"
Content="="
Margin="5"
Grid.Row="5"
Grid.Column="3"/>
</Grid>
06.1 Grid 기본 구조
Grid의 가장 기본적인 구조는, 입력한 모든 컨트롤을 사용할 수있는 최대 공간을 사용합니다.
그리고 서로의 위에 겹쳐지게 놓습니다.
마지막으로 정의한 컨트롤이 가장 위로 배치됩니다.
버튼 태그 여러개를 추가해 확인해봅시다.
<Grid>
<Button>Button 1</Button>
<Button>Button 2</Button>
</Grid>
06.2 Grid 사용 목적
일반적인 Grid의 사용 목적은, 공간을 나누어 사용하는것에 있습니다.
<Grid>
<Grid.ColumnDefinitions>
<ColumnDefinition Width="*" />
<ColumnDefinition Width="*" />
</Grid.ColumnDefinitions>
<Button>Button 1</Button>
<Button Grid.Column="1">Button 2</Button>
</Grid>
06.3 Grid 열과 행 (Rows & Column) + 비율 조정
ColumnDefinitions Width="50" 처럼 너비 속성에 수치를 입력하면, 입력한 수치만큼 크기가 할당됩니다. ColumnDefinitions Width="*" 처럼 너비 속성에 *을 입력하면, 수치값을 제외한 나머지 공간의 비율로 계산됩니다.
- Width 속성으로 * 이 1개라면 나머지 전체
- Width 속성으로 * 이 2개라면 1:1 비율
- Width 속성으로 * 이 3개라면 1:1:1 비율
- Width 속성으로 * 이 1개, Width 속성으로 2* 1개라면 1:2 비율
<Grid>
<Grid.ColumnDefinitions>
<ColumnDefinition Width="50" />
<ColumnDefinition Width="*" />
<ColumnDefinition Width="2*" />
</Grid.ColumnDefinitions>
<Button>Button 1</Button>
<Button Grid.Column="1">Button 2</Button>
<Button Grid.Column="2">Button 3</Button>
</Grid>
<Grid>
<Grid.RowDefinitions>
<RowDefinition Height="50" />
<RowDefinition Height="*" />
<RowDefinition Height="*" />
<RowDefinition Height="3*" />
</Grid.RowDefinitions>
<Button>Button 1</Button>
<Button Grid.Row="1">Button 2</Button>
<Button Grid.Row="2">Button 3</Button>
<Button Grid.Row="3">Button 4</Button>
</Grid>
세 번째 버튼은 Auto로 설정했고, 마지막에는 50 픽셀의 정적 너비를 지정했습니다.
세 번째 버튼은 텍스트를 렌더링하는 데 필요한 공간만 자동(Auto)으로 맞춰 차지하고, 네 번째 버튼은 정확히 지정된 50 픽셀만 자지합니다. 첫 번째, 두 번재 버튼은 남아있는 영역을 차지하는 가변 폭이 사용니다.
<Grid>
<Grid.ColumnDefinitions>
<ColumnDefinition Width="1*" />
<ColumnDefinition Width="1*" />
<ColumnDefinition Width="Auto" />
<ColumnDefinition Width="50" />
</Grid.ColumnDefinitions>
<Button>Button 1</Button>
<Button Grid.Column="1">Button 2</Button>
<Button Grid.Column="2">Button 3 with long text</Button>
<Button Grid.Column="3">Button 4</Button>
</Grid>
06.4 Grid 행열 구조
Grid.ColumnDefinitions 과 Grid.RowDefinitions 을 적절히 활용하면, Grid를 표 형태의 레이아웃을 만들 수 있습니다.
그리고 Grid.Row 및 Grid.Column 속성을 사용하여 격자 안에 컨트롤을 배치할 수 있습니다.
첫번째 행과 열은 0 부터 위치를 지정합니다.
<Grid>
<Grid.ColumnDefinitions>
<ColumnDefinition Width="*" />
<ColumnDefinition Width="2*" />
</Grid.ColumnDefinitions>
<Grid.RowDefinitions>
<RowDefinition Height="*" />
<RowDefinition Height="2*" />
</Grid.RowDefinitions>
<Button>Button 1</Button>
<Button Grid.Row="1">Button 2</Button>
<Button Grid.Column="2">Button 3</Button>
<Button Grid.Row="1" Grid.Column="2">Button 4</Button>
</Grid>
<Grid>
<Grid.ColumnDefinitions>
<ColumnDefinition Width="2*" />
<ColumnDefinition Width="1*" />
<ColumnDefinition Width="1*" />
</Grid.ColumnDefinitions>
<Grid.RowDefinitions>
<RowDefinition Height="2*" />
<RowDefinition Height="1*" />
<RowDefinition Height="1*" />
</Grid.RowDefinitions>
<Button>Button 1</Button>
<Button Grid.Column="1">Button 2</Button>
<Button Grid.Column="2">Button 3</Button>
<Button Grid.Row="1">Button 4</Button>
<Button Grid.Column="1" Grid.Row="1">Button 5</Button>
<Button Grid.Column="2" Grid.Row="1">Button 6</Button>
<Button Grid.Row="2">Button 7</Button>
<Button Grid.Column="1" Grid.Row="2">Button 8</Button>
<Button Grid.Column="2" Grid.Row="2">Button 9</Button>
</Grid>
06.5 Grid 여러칸 확장 span 적용
Grid에 적용된 컨트롤이 여러칸의 행렬 공간을 차지할 수 있습니다.
Span 속성을 적절히 이용합니다.
<Grid>
<Grid.ColumnDefinitions>
<ColumnDefinition Width="*" />
<ColumnDefinition Width="*" />
<ColumnDefinition Width="2*" />
</Grid.ColumnDefinitions>
<Grid.RowDefinitions>
<RowDefinition Height="*" />
<RowDefinition Height="2*" />
</Grid.RowDefinitions>
<Button>Button 1</Button>
<Button Grid.Row="1" Grid.ColumnSpan="2">Button 2</Button>
<Button Grid.Column="1" Grid.ColumnSpan="2">Button 3</Button>
<Button Grid.Row="1" Grid.Column="2">Button 4</Button>
</Grid>
<Grid>
<Grid.ColumnDefinitions>
<ColumnDefinition Width="1*" />
<ColumnDefinition Width="1*" />
</Grid.ColumnDefinitions>
<Grid.RowDefinitions>
<RowDefinition Height="*" />
<RowDefinition Height="*" />
</Grid.RowDefinitions>
<Button>Button 1</Button>
<Button Grid.Column="1">Button 2</Button>
<Button Grid.Row="1" Grid.ColumnSpan="2">Button 3</Button>
</Grid>
06.6
Grid는 기본적으로 자식 컨트롤의 HorizontalAlignment 및 VerticalAlignment 속성이 Stretch로 설정되어 있기 때문에, 사용 가능한 공간을 모두 차지합니다.
컨트롤이 필요한 공간만을 차지하고,Grid에 배치하기를 원할 수 있습니다. 가장 쉬운 방법은 조정하려는 컨트롤에 HorizontalAlignment 및 VerticalAlignment 속성을 직접 설정하는 것입니다.
<Grid>
<Grid.ColumnDefinitions>
<ColumnDefinition Width="*" />
<ColumnDefinition Width="*" />
<ColumnDefinition Width="2*" />
</Grid.ColumnDefinitions>
<Grid.RowDefinitions>
<RowDefinition Height="*" />
<RowDefinition Height="*" />
<RowDefinition Height="2*" />
</Grid.RowDefinitions>
<Button>Button 1</Button>
<Button Grid.Row="1" Grid.ColumnSpan="2" Grid.RowSpan="2"
HorizontalAlignment="Center">Button 2</Button>
<Button Grid.Column="1" Grid.ColumnSpan="2"
VerticalAlignment="Center">Button 3</Button>
<Button Grid.Row="1" Grid.Column="2" Grid.RowSpan="2"
VerticalAlignment="Center" HorizontalAlignment="Right">Button 4</Button>
</Grid>
06.7 사용자 지정 Grid - GridSplitter
Grid 패널을 사용하면 사용 가능한 공간을 개별 셀로 쉽게 분할 할 수 있습니다.
지정된 행과 열이 차지하는 공간을 사용자가 변경할 수 있게 구현할 수도 있습니다.
GridSplitter 컨트롤을 이용합니다.
<Grid>
<Grid.ColumnDefinitions>
<ColumnDefinition Width="*" />
<ColumnDefinition Width="5" />
<ColumnDefinition Width="*" />
</Grid.ColumnDefinitions>
<TextBlock FontSize="40" HorizontalAlignment="Center"
VerticalAlignment="Center"
TextWrapping="Wrap">Left side
</TextBlock>
<GridSplitter Grid.Column="1" Width="5"
HorizontalAlignment="Stretch" />
<TextBlock Grid.Column="2" FontSize="40"
HorizontalAlignment="Center"
VerticalAlignment="Center"
TextWrapping="Wrap">Right side
</TextBlock>
</Grid>
<Grid>
<Grid.RowDefinitions>
<RowDefinition Height="*" />
<RowDefinition Height="5" />
<RowDefinition Height="*" />
</Grid.RowDefinitions>
<TextBlock FontSize="55" HorizontalAlignment="Center"
VerticalAlignment="Center"
TextWrapping="Wrap">Top
</TextBlock>
<GridSplitter Grid.Row="1" Height="5" HorizontalAlignment="Stretch" />
<TextBlock Grid.Row="2" FontSize="55"
HorizontalAlignment="Center"
VerticalAlignment="Center"
TextWrapping="Wrap">Bottom
</TextBlock>
</Grid>