WPF(Windows Presentation Foundation)
MS의 새로운 프리젠테이션 프레임워크로 기존 프레임워크에서 제공하던 GDI, GDI+, HTML등을 포함할 뿐만 아니라 다양하고 새로운 여러 기능과 프레임워크를 제공합니다.
WPF의 주요특징
1. Control, 텍스트, UI 등의 여러요소가 '컨텐츠' 라는 하나의 모델로 통합되었습니다.
2. 컨텐츠를 자동으로 설정해주는 '컨테이너' 요소는 멋진 레이아웃을 만들 수 있도록 도움을 줍니다.
3. DirectX 기반으로 개발되어 WinForm에서 하기 어려웠던 3D 환경의 컨텐츠를 쉽게 생산할 수 있습니다.
4. UI로직( XAML ) 과 데이터 로직( CS ) 가 구분되어있어 디자이너와 프로그래머간의 협업이 개선되었습니다.
5. 그래픽 기능뿐만 아니라, 스트리밍, 동영상, 문서화 기능 등 다양한 기능을 사용할 수 있습니다.
일반적으로 UI작업은 디자이너가 XAML 언어를 사용하여 UI를 제작하고
프로그램 로직은 프로그래머가 .Net 언어(C#)를 사용하여 기능을 제작합니다.
이렇게 나누어 작업하면 서로 독립적으로 작업을 진행할 수 있고 프로그램 유연성을 높여 프로그램 생산성이 좋아집니다. WPF는 이러한 협업을 통해 빠르고쉽게 개발할 수 있도록 결합하여 작업할 수 있는 환경을 제공합니다.
UI 작업은 .Net 프로그램 언어로도 작업할 수 있으나, 프로그래머가 일일히 코딩해야하기에 XAML로 작성하는것보다 생산성은 떨어지나, 프로그래머가 직접 UI의 속성 등을 설정할 수 있는 장점이 있습니다.
목차
- XAML(자멜) - UI
- 컨텐츠 - UI
- 이벤트 - 데이터 로직
1. XAML ( 자멜 ) - UI
XAML은 XML 기반의
언어로, XAML 컴파일러를
이용하여 .Net(C#) 형식으로
변환됩니다.
그 후, Net 바이너리(.dll, .exe)로
결합됩니다.
아래의 그림은 XAML로 작성한 UI 입니다.
<Window x:Class="Sample.MainWindow"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
Title="MainWindow"
Height="300" Width="300">
</Window> |
1. xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
XML의 기본 네임스페이스(namespace) 문법으로, XAML에서 클래스나 속성, 이벤트를 사용하는데 쓰입니다.
"http://schemas.microsoft.com/winfx/2006/xaml/presentation"을 기본 namespace로 사용한다는 의미입니다.
2. xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
' x ' 라는 namespace ( namesapce x )를 XAML 코드에서 사용한다는 의미로
클래스, 속성, 이벤트 등에 ' namespace x ' 를 사용해야합니다.
예시 ) <Window x:Class="Sample.MainWindow"
3. Title="MainWindow" Height="300" Width="300">
MainWindow의 Title 속성과 Heigth, Width의 속성값 입니다.
2. 컨텐츠 - UI
WinForm과 같은 컨트롤들은 각 컨트롤이 수행하는 ‘기능’과 ‘UI’가 정해져 있었습니다.
또한 컨트롤의 UI을 변경하는 것은 간단한 문자열을 변경하거나 비트맵을 그리는 정도였습니다.
멋진 UI를 사용하기 위해서는 사용자정의컨트롤을 사용해야 했습니다.
WPF는 사용자정의컨트롤을 사용하지 않고 XAML에서 컨텐츠를 사용함으로써 UI를 맘껏 변경할 수 있습니다.
컨텐츠는 Windows Form, Control , TextBox 등 모든 요소가 컨텐츠 입니다. Button의 Text 속성도 컨텐츠입니다.
또한, ContentControl(부모)로부터 파생된 하나의 컨텐츠(자식)만을 가질 수 있습니다.
즉, 하나의 Form에는 버튼 1개만 생성 할 수 있습니다.
그래서 하나의 Form에 무한개의 버튼을 만들 수 있는 Panel이라는 레이아웃이 있습니다.
패널
|
특징
|
겹침
|
Canvas
|
가장 기본적인 패널로
자식 요소를 원하는 위치에 배치할 수 있다.
|
O
|
StackPanel
|
가로나 세로 방향으로
자식 요소를 일렬로 정렬한다.
|
X
|
WrapPanel
|
StackPanel과 비슷하지만 자식
요소를 왼쪽에서 오른쪽으로 차례로 배치하며 크기를 벗어나면 다음 줄에 배치한다.
|
X
|
DockPanel
|
각 지정 방향에 자식
요소를 배치한다.
|
X
|
Grid
|
가장 강력한 패널로
표 형태로 자식 요소를 배치한다.
|
O
|
2.1 Canvas Panel
가장 기본적인 패널로, 자식 요소를 원하는 위치(절대 위치)에 배치할 수 있으며, 가장 단순합니다.
Canvas 패널은 윈폼의 그리기 영역과 가장 유사한 패널로 일반적으로 그래픽 콘텍츠를
배치(그리기)하고자 할 때 유용하게 사용할 수 있습니다. 핵심 속성은 Canvas.Left, Canvas.Top,
Canvas.Right, Canvas.Bottom 입니다.
사용 예시
<Window x:Class="Sample.MainWindow" xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation" xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml" Title="MainWindow"
Height="350" Width="525"> <Canvas Background="Beige">
<Button Canvas.Left="10" Canvas.Top="10" Width="80" Height="25" Content="1"/>
<Button Canvas.Left="10" Canvas.Top="40" Width="80" Height="25" Content="2"/>
<Button Canvas.Left="10" Canvas.Top="70" Width="80" Height="25" Content="3"/>
<Ellipse Canvas.Right="10" Canvas.Top="10" Width="80" Height="25" Fill="Blue"/>
<Ellipse Canvas.Right="10" Canvas.Top="40" Width="80" Height="25" Fill="Blue"/>
<Ellipse Canvas.Right="10" Canvas.Top="70" Width="80" Height="25" Fill="Blue"/> </Canvas>
</Window> |
<Canvas Background="Beige">
Canvas Panel의 배경색을 베이지색으로 설정했습니다.
<Button Canvas.Left="10" Canvas.Top="10" Width="80" Height="25" Content="1"/>
버튼 컨텐츠에 여러 속성값을 입력할 수 있습니다.
Canvas.Left="10" : Canvas Panel의 왼쪽으로부터 10만큼 떨어져있는다.
Canvas.Top="10" : Canvas Panel의 위쪽으로부터 10만큼 떨어져있는다.
Content="1" : 버튼 컨텐츠의 내용을 1로 설정한다.
§ Panel.ZIndex 속성을 사용하여 컨테츠가 겹쳤을때 어떤것이 위에 보일지 우선순위를 설정할 수 있다.
속성 값이 클수록 우선순위가 높다. ( 즉, 겹쳤을때 보인다. )
2.2 Stack Panel
자식 요소를 행(세로)이나 열(가로)로 자동 정렬하여 배치해주는 패널입니다.
보통 다른 패널과 결합되어 많이 사용됩니다.
사용 예시
<Window x:Class="Sample.MainWindow" xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation" xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml" Title="MainWindow" Height="350" Width="525"> <StackPanel Background="Pink"> <Button Content="1"/> <Button Content="2"/> <Button Content="3"/> <Ellipse Width="80" Height="25" Fill="Blue"/> <Ellipse Width="80" Height="25" Fill="CornflowerBlue"/> <Ellipse Width="80" Height="25" Fill="CadetBlue"/> </StackPanel> </Window> |
StackPanel은 디폴트로 Orientation="Vertical" 속성값이 지정되어있어 세로로 정렬됩니다.
Fill="Blue" : 버튼 컨텐츠의 배경색을 Blue로 채운다.
§ StackPanel 요소에 Orientation="Horizontal" 속성값을 주면 가로로 배치됩니다.
§ StackPanel의 자식 요소에 Padding="10" 속성값을 주면 버튼 컨텐츠 안에 여백을 줍니다.
§ StackPanel의 자식 요소에 Margin="10" 속성값을 주면 버튼 컨텐츠 밖에 여백을 줍니다.
§ StackPanel의 자식 요소에 HorizontalAlignment="Left" 속성값을 주면 왼쪽으로 맞춰 배치됩니다.
2.3 Wrap Panel
WrapPanel의 기본 동작은 StackPanel과 같습니다.
다른 점은 자식 요소가 패널의 크기를 벗어나면
다음 줄에 자동으로 배치해줍니다.
사용 예시
<WrapPanel Background="Pink">
<Button Width="70" Content="1"/>
<Button Width="70" Content="2"/>
<Button Width="70" Content="3"/>
<Ellipse Width="80" Height="25" Fill="Blue"/>
<Ellipse Width="80" Height="25" Fill="CornflowerBlue"/>
<Ellipse Width="80" Height="25" Fill="CadetBlue"/>
</WrapPanel> |
2.4 Dock Panel
DockPanel은 전체 레이아웃을 표현할 때 주로 사용하고, 패널에서 지정한 방향으로 항목을 배치합니다.
자식 요소를 지정한 방향으로 배치시키고 마지막 자식 요소는 남은 공간을 채우도록 배치합니다.
Canvas와 같이 DockPanel도
DockPanel.Dock 이란 결합 속성을 사용하며 이 결합 속성을 사용하여 자식 요소들이 지정한 방향에 배치됩니다.
사용 예시
<DockPanel LastChildFill="False" Background="Pink">
<Button DockPanel.Dock="Left" Width="50" Content="1"/>
<Button DockPanel.Dock="Top" Height="100" Content="2"/>
<Button DockPanel.Dock="Right" Width="50" Content="3"/>
<Button DockPanel.Dock="Bottom" Content="4"/>
<Button Content="마지막 버튼"/>
</DockPanel> |
Dock한 순서대로 배치됩니다.
DockPanel.Dock="Left" : Dock Panel의 왼쪽으로 배치한다.
LastChildFill ="False" : 남은 공간을 채우지 않고 남겨 놓습니다.
2.5 Grid Panel
Grid 패널은 자식 요소를 표 형태로 배치하며, 자식 요소들 간의 간격과 배율을 유지 시킬 수 있습니다.
행과 열로 이루어진 Grid는 셀( Cell )이라 부르는 행, 열의 위치에 자식 요소를 배치하거나 여러 셀에 자식 요소를 배치할 수 있다. 즉, Excel 같은 패널입니다.
주로, 그리드로 UI 구조의 큰 틀을 잡고 패널을 사용해 세부적인 UI를 꾸밉니다.
사용 예시
1. 기본적인 Grid 패널
<Grid ShowGridLines="True">
<Grid.RowDefinitions>
<RowDefinition />
<RowDefinition />
</Grid.RowDefinitions>
<Grid.ColumnDefinitions>
<ColumnDefinition />
<ColumnDefinition />
<ColumnDefinition />
</Grid.ColumnDefinitions>
<Button Grid.Row="0" Grid.Column="0" Margin="5" Content="1" />
<Button Grid.Row="0" Grid.Column="1" Margin="5" Content="2" />
<Button Grid.Row="0" Grid.Column="2" Margin="5" Content="3" />
<Button Grid.Row="1" Grid.Column="0" Margin="5" Content="4" />
<Button Grid.Row="1" Grid.Column="1" Margin="5" Content="5" />
<Button Grid.Row="1" Grid.Column="2" Margin="5" Content="6" />
</Grid> |
ShowGridLines="True" : 셀들의 경계를 확인하기 위해 점선을 출력합니다.
<Grid.RowDefinitions> : RowDefinition 요소를 사용하여 행의 개수를 결정합니다.
<Grid.ColumnDefinitions> : ColumnDefintion 요소를 사용하여 행의 개수를 결정합니다.
Grid.Row="0" : 몇번째 행인지에 대한 값.
Grid.Column="0" : 몇번째 열인지에 대한 값.
2. 여러 셀을 하나로 합지는 Grid
<Grid ShowGridLines="True">
<Grid.RowDefinitions>
<RowDefinition />
<RowDefinition />
</Grid.RowDefinitions>
<Grid.ColumnDefinitions>
<ColumnDefinition />
<ColumnDefinition />
<ColumnDefinition />
</Grid.ColumnDefinitions>
<Button Grid.Row="0" Grid.Column="0" Grid.RowSpan="2" Margin="5" Content="1" />
<Button Grid.Row="0" Grid.Column="1" Margin="5" Content="2" />
<Button Grid.Row="0" Grid.Column="2" Margin="5" Content="3" />
<Button Grid.Row="2" Grid.Column="1" Grid.ColumnSpan="2" Margin="5" Content="5" />
</Grid> |
Grid.RowSpan="2" : 몇개의 행을 합칠것인가에 대한 값.
Grid.ColumnSpan="2" : 몇개의 열을 합칠것인가에 대한 값.
3. 정적 Column(열)의 크기 지정
<Grid ShowGridLines="True" Background="LightBlue">
<Grid.RowDefinitions>
<RowDefinition />
<RowDefinition />
</Grid.RowDefinitions>
<Grid.ColumnDefinitions>
<ColumnDefinition Width="100"/>
<ColumnDefinition Width="150"/>
<ColumnDefinition Width="200"/>
</Grid.ColumnDefinitions>
<Button Grid.Row="0" Grid.Column="0" Margin="5" Content="1번" />
<Button Grid.Row="0" Grid.Column="1" Margin="5" Content="2번" />
<Button Grid.Row="0" Grid.Column="2" Margin="5" Content="3번 컨텐츠가 긴 버튼" />
<Button Grid.Row="2" Grid.Column="0" Margin="5" Content="4번 컨텐츠가 긴 버튼" />
<Button Grid.Row="2" Grid.Column="1" Margin="5" Content="5번" />
<Button Grid.Row="2" Grid.Column="2" Margin="5" Content="6번" />
</Grid> |
4. 동적 Column(열)의 크기 지정
<Grid ShowGridLines="True" Background="LightBlue">
<Grid.RowDefinitions>
<RowDefinition />
<RowDefinition />
</Grid.RowDefinitions>
<Grid.ColumnDefinitions>
<ColumnDefinition Width="Auto"/>
<ColumnDefinition Width="Auto"/>
<ColumnDefinition Width="Auto"/>
</Grid.ColumnDefinitions>
<Button Grid.Row="0" Grid.Column="0" Margin="5" Content="1번 버튼" />
<Button Grid.Row="0" Grid.Column="1" Margin="5" Content="2번" />
<Button Grid.Row="0" Grid.Column="2" Margin="5" Content="3번 컨텐츠가 긴 버튼" />
<Button Grid.Row="2" Grid.Column="0" Margin="5" Content="4번 컨텐츠가 긴 버튼" />
<Button Grid.Row="2" Grid.Column="1" Margin="5" Content="5번" />
<Button Grid.Row="2" Grid.Column="2" Margin="5" Content="6번" />
</Grid> |
5. 배율로 Column(열)의 크기 지정
<Grid ShowGridLines="True" Background="LightBlue">
<Grid.RowDefinitions>
<RowDefinition />
<RowDefinition />
</Grid.RowDefinitions>
<Grid.ColumnDefinitions>
<ColumnDefinition Width="Auto"/>
<ColumnDefinition Width="1*"/>
<ColumnDefinition Width="2*"/>
</Grid.ColumnDefinitions> |
6. 서로 다른 Grid의 열 크기 공유
<Grid Grid.IsSharedSizeScope="True">
<Grid.RowDefinitions>
<RowDefinition />
<RowDefinition />
</Grid.RowDefinitions>
<Grid Grid.Row="0" ShowGridLines="True" Background="Yellow">
<Grid.RowDefinitions>
<RowDefinition />
<RowDefinition />
</Grid.RowDefinitions>
<Grid.ColumnDefinitions>
<ColumnDefinition SharedSizeGroup="Group1"/>
<ColumnDefinition Width="200" SharedSizeGroup="Group2"/>
<ColumnDefinition SharedSizeGroup="Group3"/>
</Grid.ColumnDefinitions>
<Button Grid.Row="0" Grid.Column="0" Margin="5" Content="1번 버튼" />
<Button Grid.Row="0" Grid.Column="1" Margin="5" Content="2번" />
<Button Grid.Row="0" Grid.Column="2" Margin="5" Content="3번 컨텐츠가 긴 버튼" />
<Button Grid.Row="2" Grid.Column="0" Margin="5" Content="4번" />
<Button Grid.Row="2" Grid.Column="1" Margin="5" Content="5번" />
<Button Grid.Row="2" Grid.Column="2" Margin="5" Content="6번" />
</Grid>
<Grid Grid.Row="1" ShowGridLines="True" Background="LightBlue">
<Grid.RowDefinitions>
<RowDefinition />
<RowDefinition />
</Grid.RowDefinitions>
<Grid.ColumnDefinitions>
<ColumnDefinition SharedSizeGroup="Group1"/>
<ColumnDefinition SharedSizeGroup="Group2"/>
<ColumnDefinition SharedSizeGroup="Group3"/>
</Grid.ColumnDefinitions>
<Button Grid.Row="0" Grid.Column="0" Margin="5" Content="7번 버튼" />
<Button Grid.Row="0" Grid.Column="1" Margin="5" Content="8번" />
<Button Grid.Row="0" Grid.Column="2" Margin="5" Content="9번" />
<Button Grid.Row="2" Grid.Column="0" Margin="5" Content="10번 컨텐츠가 긴 버튼" />
<Button Grid.Row="2" Grid.Column="1" Margin="5" Content="11번" />
<Button Grid.Row="2" Grid.Column="2" Margin="5" Content="12번" />
</Grid>
</Grid> |
두 Gird 패널을 포함하는 부모 Grid 패널이 IsSharedSizeScope 속성을 True로 설정해야 크기가 공유됩니다.
Grid.IsSharedSizeScope="True" : True |크기 공유. False | 크기 공유 No.
SharedSizeGroup="Group1" : 같은 Value(값)를 가진 그룹은 하나의 열처럼 동작합니다.
3. 이벤트 - 데이터로직
1. 마우스 이벤트
기본클래스 <UIElement>로부터 파생되었습니다.
MouseDown, MouseUp등의 마우스의 동작과 관련된 이벤트를 정의하고 있습니다.
이런 이벤트는 입력과 관련된 기본 클래스인 InputEventArgs로부터 상속받은 MouseEventArgs 대리자를 통해
마우스와 관련된 여러 정보를 확인할 수 있습니다.
사용예시
마우스를 클릭했을 때, 사각형이 출력되는 예제
[ XAML 코드 ] <Windows> <Canvas Name="canvas" Background="LightBlue" MouseLeftButtonUp="canvas_MouseLeftButtonUp">
</Canvas> </Windows>
[ CS 코드 ] private void Canvas_LeftMouseUp(object sender, MouseButtonEventArgs e) { Point pos = e.GetPosition(canvas); // 마우스 좌표값을 얻어옵니다.
Rectangle rt = new Rectangle(); // 사각형 객체를 생성합니다. rt.Width = 50; rt.Height = 50; rt.Stroke = new SolidColorBrush(Colors.AliceBlue); // 겉 테두리 색상을 설정합니다. rt.Fill = new SolidColorBrush(Colors.Aqua); // 안의 배경색상을 설정합니다.
Canvas.SetLeft(rt, ps.X); // Canvas를 기준으로 좌표값을 설정합니다. Canvas.SetTop(rt, ps.Y);
canvas.Children.Add(rt); // canvas에 객체를 생성합니다. } |
1. Canvas에 MouseLeftButtonUp="canvas_MouseLeftButtonUp" 속성값을 통해 마우스 이벤트를
CS파일에 생성합니다.
2. CS파일에서 로직을 코딩합니다.
3. 실행하여 동작을 확인합니다.
§ IsMouseOver 속성은 자신을 포함한 자식 요소까지 포함하여 마우스가 존재하면 True
§ IsMouseDirectlyOver 속성은 자신 위에만 마우스가 존재하면 True
2. 키보드 이벤트
기본클래스 <UIElement>로부터 키보드 관련 기능을 제공받습니다.
KeyDown, KeyUp등의 이벤트를 KeyEventArgs 핸들러로 전달된다.
사용예시
[ XAML 코드 ] <Window x:Class="ex_3_05.MainWindow"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
Title="MainWindow"
Height="350" Width="525" KeyDown="Window_KeyDown">
<Canvas Name="canvas" Background="LightBlue">
</Canvas>
</Window>
[ CS 코드 ] private void Window_KeyDown(object sender, KeyEventArgs
e) { Title =
e.Key.ToString();
} |
3. 라우트 이벤트
3.1 터널링 이벤트
부모요소로부터 자식요소로 이벤트가 라우팅(전달)하는 이벤트입니다.
이벤트 접두어로 Preview 가 붙어 PreviewMouseDown 식의 이벤트 이름을 사용합니다.
3.2 버블링 이벤트
자식요소로부터 부모요소로 이벤트가 라우팅(전달)하는 이벤트입니다.
MouseDown 식의 이벤트 이름을 사용합니다.
댓글