본문 바로가기

.Net Technology/WPF

(2)WPF 애플리케이션의 다양한 특징과 어셈블리

WPF 애플리케이션의 다양한 특징들

WPF API는 다양한 GUI 애플리케이션을 만드는데 이용될 수 있지만 어떤 목적이냐에 따라서 개발 방법이나 구조가 조금 달라지게 된다. 이번에는 이러한 각각의 개발 모델에 대해서 간단하게 살펴보도록 하겠다. 

전형적인 데스크탑 애플리케이션

먼저 전형적인 모델은 로컬 머신에 어셈블리를 실행하는 것이다. 예를 들어 WPF를 이용해서 텍스트 에디터를 만들었거나 페인팅 프로그램 아니면 디지털 플레이어, 포토앨범과 같은 멀티미디어 프로그램들이 여기에 해당될 것이다. 다른 데스크탑 애플리케이션처럼 *.exe 파일로 컴파일 되어 윈도우 인스톨러나 클릭온스(ClickOnce)와 같은 기술을 이용해서 실행될 수 있을 것이다. 

이런 관점으로 살펴본다면 WPF는 간단하게 전형적인 데스크탑을 만드는 새로운 API이다. 프로그램적인 관점으로 본다면 WPF 애플리케이션의 클래스는 Window와 Application을 이용해서 만들 수 있고 추가적으로 대화상자나 메뉴, 툴바, 상태 바와 같은 UI 요소를 추가할 수 있을 것이다. 

네비게이션 기반의 WPF 애플리케이션

WPF 애플리케이션은 네비게이션 기반의 구조로 설계하여 개발할 수 있다. 즉, 전형적인 데스크탑 애플리케이션을 웹 브라우저에서처럼 실행된다는 것으로 이해하면 된다. 이 프로그래밍 모델은 데스크탑 애플리케이션처럼 *.exe 실행파일이 생성되고 [앞], [뒤]와 같은 버튼을 제공해주어 다양한 UI 화면을 앞뒤로 탐색할 수 있게 지원해준다. 이 애플리케이션은 스스로 각각의 페이지를 리스트로 가지고 있기 때문에 그 페이지를 앞뒤로 탐색할 수 있다. 그리고 히스토리 리스트를 유지하고 있고 다른 페이지로 데이터를 넘기는 것 또한 가능하다. 그 예로 비스타의 윈도우 탐색기를 예로 들 수 있다. 다음 [그림1]에서 보여지는 것처럼 오른쪽, 왼쪽을 가리키는 탐색 버튼과 히스토리를 보여주는 리스트들을 볼 수 있다. 

WPF는 데스크탑 애플리케이션임에도 불구하고 웹과 같은 네비게이션 기능을 제공해 주고 있기 때문에 보가 간단하게 UI 디자인을 구현할 수 있다. 또한 이 애플리케이션은 데스크탑에서 동작되는 프로그램 보다 더 가볍다. 그리고 웹 애플리케이션과는 모양이 비슷하긴 하지만 특별한 관계가 있는 것은 아니다. 프로그래밍 관점으로 이 애플리케이션의 구조는 Page, NavigationWindow, Frame과 같은 클래스들을 이용해서 현재의 페이지를 렌더링하게 된다. 

 
[그림1] 네비게이션 기반의 데스크탑 프로그램


XBAP 애플리케이션

WPF 애플리케이션은 웹 브라우저 안에 임베디드 되어 보여줄 수 있는 기능을 제공해주고 있다. WPF 제공하는 이 기능을 우리는 XAML 브라우저 애플리케이션이나 XBAP 이라고 부른다. 이 프로그래밍 모델을 이용하면 사용자는 URL 기반으로 접근할 수 있고 XBAP 애플리케이션은 로컬에 다운로드 되고 인스톨되어 간단하게 동작된다. 윈도우 애플리케이션을 실행하기 위해서 사용해 오던 클릭온스 와는 다르게 XBAP는 브라우저 안에 임베디드 되어 실행된다. 다음 [그림2]는 XBAP에서 동작되는 모습을 보여주고 있다. 
 

[그림2] 로컬에 다운로드 되고 웹 브라우저에 임베디드 되는 XBAP 프로그램

XBAP의 단점 중에 하나가 인터넷 익스플로러 6.0 이상의 버전과 파이어폭스만 지원한다는 것이다. 만약 인트라넷과 같은 프로그램을 인터넷을 통하여 배포한다고 한다면 브라우저 호환성에 있어서 문제가 생길 수 있다. 하지만 만약 IE와 파이어폭스만 이용하게 할 수 있다면 XBAP를 만드는 것도 나쁘지 않을 것이다. 하지만 몇몇의 사용자는 WPF의 XBAP 애플리케이션을 못 볼 수도 있다는 것을 알아두자. 

XBAP 애플리케이션의 다른 이슈는 인터넷 존(Internet Zone)이라는 보안 인증기반으로 동작 된다는 것이다. 20장에서 살펴 보았듯이 인터넷 존 인증기반으로 동작될 경우 로컬에 있는 리소스들에 접근하는데 있어서 다소 제약이 있고 닷넷의 모든 기능을 자유롭게 사용하는데 있어서 다소 제한이 있을 수 있다. 특별히 XBAP의 경우 다음과 같은 기능의 제한이 따른다.

- 윈도우 독립적인 화면을 만드는 것
- 직접 정의한 대화상자를 보여주는 것
- Save 대화상자를 보여주는 것
- 로컬에 있는 파일에 접근하는 것
- 윈도우 애플리케이션, ActiveX와 같은 레거시 모듈을 임베디드 시키는 것



이와 같이 XBAP은 대화상자와 같은 다른 윈도우 폼을 만드는데 있어서 제약이 있다. 앞에서도 언급했듯이 실제로 XBAP은 페이지 기반의 사용자 인터페이스로 여러 명의 사용자들에게 공개할 수 있는 기능이 핵심부분이라는 것을 알아두자. 


실버라이트 애플리케이션

WPF와 XAML은 실버라이트(Silverlight)라는 플러그인을 통하여 크로스 플랫폼을 지원하고 있다. 실버라이트 SDK를 이용하면 마이크로소프트의 윈도우뿐만 아니라 Mac OS X에서도 지원이 가능한 브라우저 기반의 애플리케이션이다. 

또한 실버라이트는 Rich 웹 애플리케이션을 만드는 차세대 웹 플랫폼이라고 할 수 있다. WPF와 같이 실버라이트 역시 벡터 그래픽을 지원하고 애니메이션을 지원한다. 그리고 텍스트 문서뿐만 아니라 멀티미디어 기능도 제공하고 있다. 지금 실버라이트2의 경우 닷넷 기반의 클래스 라이브러리를 제공해주고 있기 때문에 쉽게 개발할 수 있다. 실버라이트는 WPF와 같은 몇 개의 컨트롤들을 지원해주고 있고 또한 LINQ와 일반적인 커넥션 타입, WCF와의 연동과 같은 다양한 기능을 지원해주고 있다. 


WPF를 위한 어셈블리들

WPF에서는 새로운 닷넷 어셈블리들이 추가되었다. 다음 [표3]에서 설명하고 있는 어셈블리들은 WPF 애플리케이션을 개발하기 위한 기본적으로 사용되는 어셈블리들이다. 각각의 어셈블리들은 새로운 프로젝트를 만들 때 참조해 주어야 한다. 만약 비주얼 스튜디오 2008을 이용해서 프로젝트를 생성된다면 자동적으로 추가될 것이다. 

이름

내용

PresentationCore.dll

이 어셈블리는 GUI 레이아웃과 관련된 다수의 클래스들이 정의되어 있다.예를 들어 이 어셈블리는 WPF Ink API를 제공해주고 있다그리고 애니메이션을 위한 클래스들을 제공해주고 있고 또한 그래픽 렌더링을 위한 클래스들을 제공해주고 있다.

PresentationFoundation.dll

WPF 컨트롤을 설정하거나 추가적인 애니메이션과 멀티미디어 클래스들을 지원해준다그리고 데이터 바인딩을 지원하고 XAML을 다루기 위한 코드 또한 제공해준다.

WindowsBase.dll

이 어셈블리는 보안에 관련된 모듈이나 컨버터 또한 Pint, Vector, Rect와 같은 WPF의 코어적인 API들을 정의하고 있다.

[표3]WPF의 기본 어셈블리들

이 세 개의 어셈블리들은 다수의 새로운 네임스페이스들을 가지고 있고 수백 개의 새로운 닷넷 클래스, 인터페이스, 구조체, enum형, 델리게이트들을 가지고 있다. 닷넷 프레임워크 3.5 SDK의 문서를 통해서 이 정의들을 살펴 볼 수 있다. 다음 [표4]는 우리가 알아야 하는 기초적인 네임스페이스들을 보여주고 있다.

이름


System.Windows

이 네임스페이스는 WPF의 최상위 네임스페이스로 Application이나Winodw와 같은 기본적인 멤버들이 포함되어 있다. WPF 프로젝트를 만들 때 반드시 필요한 네임스페이스라고 보면 된다.

System.Windows.Controls

메뉴툴팁 그리고 다수의 레이아웃 매니저와 같은 WPF의 컨트롤들을 포함하고 있다.

System.Windows.Markup 

이 네임스페이스는 XAML의 마크업을 파싱하고 처리하기 위한 다수의 클래스들을 지원하고 있다

System.Windows.Media

미디어 처리를 담당하는 Media 네임스페이스들에 최상위 네임스페이스이다주로 애니메이션이나 텍스트 렌더링과 같은 멤버들이 정의 되어있다

System.Windows.Navigation

이 네임스페이스는 XBAP이나 네비게이션 기반의 애플리케이션을 만드는데 필요한 멤버들을 제공하고 있다.

System.Windows.Shapes

이 네임스페이스는 다양한 2D그래픽(Rectangle, Polygon) 멤버들을 제공하고 있다

[표4] WPF의 코어 네임스페이스

WPF 프로그래밍을 시작하기 전에 먼저 System.Windows 에서 제공하고 있는 Application과 Window라는 두 가지 멤버들에 대해서 먼저 살펴보도록 하겠다. 


Application 클래스의 역할

System.Windows.Application 클래스는 WPF 애플리케이션을 구동하기 위한 전역 인스턴스이다. 윈도우 폼처럼 Run()이라는 메서드를 제공하고 있고 애플리케이션의 생명주기에 대한 이벤트를 제공하고 있다. 그리고 XAML 브라우저에서 사용되는 다양한 멤버들 또한 가지고 있다. 다음 [표5]는 우리가 알아야 할 Application의 중요한 멤버들을 보여주고 있다. 

이름

설명

Current 

이 속성은 스태틱으로 선언되어 있고 현재 실행중인 Application 객체를 반환한다이 속성은 새로 생성한 윈도우나 대화상자에서 현재 생성된 Application 객체에 접근하고 싶을 때 유용하게 사용할 수 있다.

MainWindow

이 속성은 애플리케이션의 메인 윈도우를 반환한다.

Properties 

이 속성은 WPF 애플리케이션 필요한 데이터를 저장하고 가져올 수 있는 저장소이다. ASP.NET application 변수와 비슷한 개념이라 보면 된다.

StartupUri

이 속성은 애플리케이션이 자동으로 실행될 때 실행할 WindowPage를 지정한다

Windows 

이 속성은 WindowCollection 클래스를 반환하며 Application 객체로부터 만들어진 윈도우들을 각각 접근할 수 있다이 객체를 이용하면 모든 애플리케이션을 최소화 하거나 할 때 매우 유용하게 사용할 수 있다


[표5] Application의 중요한 속성

윈도우 폼과는 다르게 WPF 애플리케이션의 클래스들의 멤버들은 모두 스태틱 멤버로 노출되어 있지 않다는 것이다. 대신에 WPF 프로그램에서는 이 클래스를 확장해서 사용하면 된다. 다음 예를 살펴보자.

// Application 객체의 정의 
class MyApp : Application
{
    [STAThread]
    static void Main()
    {
        // 이벤트를 설정하거나 메인 윈도우의 노출
    }
}


다음 예제에서 Application을 상속받은 애플리케이션을 구현할 것이기 때문에 여기서는 Window 타입의 기능에 대해서만 숙지하도록 하자. 이제 Window 클래스가 제공하고 있는 다수의 기초 클래스들에 대해서 살펴보도록 하자.


Window 클래스의 역할

System.Windows.Window 클래스는 Application을 상속받은 하나의 창일 수도 있고 또한 대화상자나 메인 윈도우와 같은 창일 수도 있다. 이미 예상했을 수도 있겠지만 Window클래스는 다수의 부모 클래스들을 가지고 있고 그 각각의 부모 클래스들은 다양한 기능들을 가지고 있다. 다음 [그림3]은 비주얼 스튜디오 2008 객체 탐색기에서 살펴본 System.Windows.Window의 계층구조를 보여주고 있다. 
 

[그림3] Window 클래스의 계층구조

위의 화면에서 보여지는 다양한 클래스들은 이번 장과 다음의 장들에서 다루는 내용을 통해서 차차 이해할 수 있을 것이지만 그전에 각각의 부모클래스들에 대해서 설명해보도록 하겠다. (이 내용은 비주얼 스튜디오 2008 SDK 문서를 이용해서 찾아볼 수 있다.)


System.Windows.Controls.ContentControl의 역할

먼저 Window의 바로 위의 부모는 ContentControl이라는 클래스이다 이 클래스는 Content를 호스트할 수 있는 기능을 가지고 있다. 이 기능은 간단하게 특정 객체를 컬렉션에 추가하고 위치시킬 수 있다. WPF는 Content를 기반으로 하고 있기 때문에 다수의 UI 개체들을 간단한 문자열을 표현하기 위한 용도 이상으로 Content를 사용하고 있다. 예를 들어 Button에서는 ScrollBar를 지원하는 Content를 정의할 수 있다. ContentControl는 Content를 지원해주는 것이 주목적이기 때문에 속성의 이름을 이렇게 정의된 것이다. 

만약 Content 속성에 간단한 문자열을 할당하고 싶다면 요소의 태그 안에 명시적으로 값을 할당해 줄 수 있을 것이다. 

<!-- 명시적으로 Content 값의 설정 -->
<Button Height="80" Width="100" Content="ClickMe"/>

이렇게 명시적으로 Content 프로퍼티에 값을 지정해 줄 수 있지만 다음과 같이 값을 지정할 수 있다. 이렇게 지정해 주어도 값을 똑같이 할당되게 된다.
 
<!-- 묵시적인 Content 값을 설정 -->
<Button Height="80" Width="100">
ClickMe
</Button>

하지만 여기서 Content 속성에 간단한 문자열 배열과 같은 값을 표현하고 싶은데 Content 애트리뷰트를 이용해서 요소 안에 넣는 것은 불가능 할 것이다. 때문에 두 번째 예제와 같은 방법으로 Content 값을 할당해 주어야 할 것이다. 그렇다면 다음 예제처럼 XAML에서 ScrollBar 클래스를 Content 속성을 선언하는 것처럼 할당했을 경우를 생각해보자.

<!-- Content처럼 Button 안에 ScrollBar를 선언 -->
<Button Height = "80" Width = "100">
  <ScrollBar Width = "75" Height = "40"/>
</Button>
<!-- 속성을 이용해서 ScrollBar를 버튼에 포함 -->
<Button Height = "80" Width = "100">
  <Button.Content>
    <ScrollBar Width = "75" Height = "40"/>
  </Button.Content>
</Button>



하지만 알아야 두어야 할 것은 WPF 컨트롤은 모두 ContentControl를 상속받지 않는다는 것이다. 그렇기 때문에 컨트롤들은 반드시 Content 기반의 모델을 지원하고 있지 않는 것이다. 특별히 Frame, GroupItem, HeaderedContentControl, Label, ListBoxItem, ButtonBase, StatusBarItem, ScrollViewer, ToolTip, UserControl 과 같은 컨트롤들과 Window는 Content 기반의 프로그래밍 모델을 지원하고 있다. 이 컨트롤을 제외하고 모두 Content 기반의 XAML을 적용한다면 컴파일 시 에러가 발생하게 될 것이다.

<!-- 에러! ScrollBars는 ContentControl를 상속받지 않고 있다. -->
<ScrollBar Height = "80" Width = "100">
  <Button Width = "75" Height = "40"/>
</ScrollBar >



다른 중요한 포인트는 ContentControl 를 상속받은 컨트롤은 단 하나의 Content 값만 할당해 줄 수 있다는 것이다. 때문에 XAML 버튼은 다음과 같이 Conent 프로퍼티에 두 개 이상의 속성을 지정하게 되면 에러가 발생하게 된다. 

<!-- TextBox와 Ellipse 2개를 셋팅하면 에러가 발생한다. -->
<Button Height = "200" Width = "200">
    <Ellipse Fill = "Green" Height = "80" Width = "80"/>
    <TextBox Width = "50" Height = "40"/>
</Button >



얼핏 보기에는 꽤 제한적으로 느껴질 수 있을 것이다. 하지만 ContentControl을 상속받은 컨트롤들은 다행히도 패널을 이용해서 여러 개의 개체들을 추가하는 것이 가능하다. 이렇게 하기 위해서는 추가되는 개체들은 패널의 한 부분으로 포함되어야만 한다는 것이고 또한 여기서도 중요한 부분은 바로 패널의 Content 속성은 하나의 값만 할당되어야만 한다는 것이다. 앞으로의 내용에서 WPF의 Content 기반의 프로그래밍 모델을 살펴볼 것이고 또한 다양한 패널 타입들에 대해서 배우게 될 것이다. 

System.Windows.ContentControl 클래스는 HasContent 속성을 제공해주고 있기 때문에 이 기능을 이용하면 Content의 속성이 현재 null인지 확인할 수 있을 것이다.



System.Windows.Controls.Control 역할

ContentControl와는 다르게 WPF의 컨트롤들은 모두 Control 클래스를 상속받고 있다. 이 클래스는 기본적은 UI 기능들을 제공해주고 있다. 예를 들어 Contorl 클래스는 컨트롤의 사이즈, 투명도, 탭 순서 로직, 색과 같은 속성들을 정의하고 있다. 게다가 이 클래스는 템플릿 서비스들을 제공해준다. 30장에서 설명할 내용이지만 WPF 컨트롤은 템플릿이나 스타일 그리고 테마를 이용해서 UI를 동적으로 변경할 수 있다. 다음 [표6]은 Control 클래스의 주용한 멤버들을 소개해주고 있다. 

이름

설명

Background, Foreground, BorderBrush, BorderThickness, Padding, HorizontalContentAlignment, VerticalContentAlignment

컨트롤을 어떻게 그리고 어디에 위치시킬 것인지를 설정한다

FontFamily, FontSize, FontStretch, FontWeight 

컨트롤의 폰트에 대한 다양한 값을 설정한다.

IsTabStop, TabIndex 

윈도우 안에 배치된 컨트롤들의 탭 순서를 설정한다.

MouseDoubleClick, PreviewMouseDoubleClick 

더블클릭 동작에 관련된 이벤트를 설정한다.

Template 

컨트롤의 템플릿을 가져가거나 원하는 렌더링대로 설정할 수 있다.

[표6] Control클래스의 주요 멤버


System.Windows.FrameworkElement의 역할

이 클래스는 WPF 프레임워크에 필요한 다수의 코어 멤버들을 가지고 있다. 이 클래스의 주요한 역할들은 스토리 보드나 데이터 바인딩을 지원하기 위한 모듈뿐만 아니라 Name 프로퍼티를 이용해서 멤버의 이름을 지정할 수 기능을 제공하고 있다. 또한 이 클래스를 상속받게 되는 클래스는 정의된 어떤 종류의 리소스든 가지고 있을 수 있다. 다음 [표7]은 주요한 멤버 변수들을 보여주고 있다. 

이름

설명

ActualHeight, ActualWidth, MaxHeight, MaxWidth, MinHeight, MinWidth,

사이즈를 설정한다.

ContextMenu 

팝업 메뉴를 설정하거나 가져온다

Cursor 

상속한 마우스의 커서를 설정하거나 가져온다.

HorizontalAlignment, VerticalAlignment 

Panel이나 ListBox 같은 컨테이너의 위치 타입을 지정한다

Name 

코드 파일에서 접근하기 위한 이름을 지정한다.

Resources 

정의된 리소스를 접근한다. (이 내용은 30장에서 자세히 살펴본다.)

ToolTip

툴팁을 설정하거나 가져온다.

[표7] FrameworkElement클래스의 주요 멤버


System.Windows.UIElement의 역할

Window에서 상속받는 클래스들 중에서 UIElement 클래스는 가장 많은 기능을 제공해주고 있다. UIElement의 중요한 역할은 컨트롤에 포커스나 입력과 같은 다수의 이벤트들을 제공해주고 있다는 것이다. 예를 들어 드래드&드랍과 같은 동작이나 마우스의 움직임, 키보드 입력과 같은 기능을 제공해주고 있다. 

29장에서 WPF의 이벤트에 대해서 자세히 살펴볼 것이다. (MouseMove, KeyUp, MouseDown, MouseEnter, MouseLeave 등) 다음 [표8]에서처럼 이벤트들은 한 다스 정도 정의되어 있고 포커스 여부, Enabled 상태, Visibility와 같은 멤버들을 제공하고 있다. 

Focusable, IsFocused 

상속 된 컨트롤의 포커스를 설정한다.

IsEnabled 

속성의 Enbled Disabled 속성을 설정한다.

IsMouseDirectlyOver, IsMouseOver 

히트 테스트(hit-testing) 기능을 제공한다.

IsVisible, Visibility, Visible

Visibility에 대한 설정을 제공한다

RenderTransform 

변형(Transformation)에 대한 값을 지정한다.

[표8] UIElement 클래스의 멤버


System.Windows.Media.Visual의 역할

Visual 클래스는 그려진 개체의 히트 테스팅(개체가 겹치거나 할 경우)을 제공해주고 있다. 실제로 이 클래스는 WPF 어셈블리와 DirextX에서 이용되는 milcore.dll(관리되지 않는 어셈블리)를 이용해서 위치에 대한 정보를 관리한다. 

30장에서 살펴볼 내용이지만, WPF는 기능성과 성능에 관점에 있어서 완전히 다른 3가지의 그래픽 렌더링 방법을 제공해주고 있다. Visual 클래스를 이용하면 그래픽 데이터를 가장 가볍게 그릴 수 있을 뿐만 아니라 수동적인 코드의 양도 많지 않다. 자세한 내용은 30장에서 살펴보도록 하겠다.

System.Windows.DependencyObject의 역할

WPF는 의존성 속성(Dependency Property)라고 불리는 기능을 지원한다. 간단하게 설명하자면 이 속성은 다른 속성의 값에 의존하여 자신의 속성을 변경한다는 것이다. 그렇기 때문에 “의존”이라는 단어를 사용하는 것이다. 이 속성을 이용하려면 당연히 DependencyObject 클래스를 상속받아야 한다. 또한 DependencyObject 클래스는 상속된 클래스의 속성들을 지정하는 것을 지원해주고 있기 때문에 WPF 데이터 바인딩이나 다양한 패널 안에 여러 UI 요소를 다룬다고 할 때 매우 유용하게 사용할 수 있을 것이다. 

DependencyObject 클래스는 GetValue()와 SetValue()라는 2개의 핵심적인 메서드를 지원한다. 이 메서드를 이용해서 프로퍼티를 설정할 수 있다. 여기서 어떤 것이 의존성 속성이고 어떤 것이 첨부속성인지 물어볼 수 있을 것이다. 의존성 속성이라는 개념은 WPF에만 존재하는 개념으로 자세한 내용은 29장에서 “새로운 프로젝트” 부분에서 자세히 살펴볼 것이다. 

System.Windows.Threading.DispatcherObject의 역할

Window의 마지막 클래스로 DispatcherObject에 대해서 설명해보도록 하겠다. 이 클래스는 Dispatcher 라는 재미있는 속성을 제공하고 있다. 이 속성은 System.Windows.Threading.Dispatcher 객체를 반환한다. Dispatcher 클래스는 WPF 애플리케이션의 큐 이벤트를 담당하게 된고 동시 접속과 스레드와 같은 기본 기능들을 처리하게 된다. 대체적으로 이 클래스는 코어 기반의 작업이 대부분이기 때문에 WPF 애플리케이션에서는 주로 무시될 수 있는 속성이다. 



이 내용은 C#.NET Platform 원서의 내용을 기반으로 작성되었습니다.