디자인과 로직 분리하기 - WPF, Sparkle, 그리고 등등등
디자인과 로직 분리하기 - WPF, Sparkle, 그리고 등등등
http://blogs.msdn.com/heejaechang/archive/2005/10/06/478048.aspx
|
디자인과 로직 분리하기 - WPF, Sparkle, 그리고 등등등
http://blogs.msdn.com/heejaechang/archive/2005/10/06/478048.aspx
강좌 오랜만에 올려봅니다 ^^;;
오늘은 Expression Blend (디자인 소프트웨어)를 연동하여 유저 인터페이스 (GUI) 를 조금 더 멋있게 디자인 하는 방법에 대해 알아보도록
하겠습니다.
우선 Expression Studio (디자인 프로그램) 계열의 Expression Blend를 실행시킵니다.
실행하시면 몇 초 후에 아래와 같은 화면이 뜨는 것을 보실 수 있는데요,
여기서 New Project (빨간색 상자 안) 버튼을 클릭하여 새로운 프로젝트 생성 대화상자를 엽니다.
이렇게 대화상자가 열리면 좌측의 메뉴 리스트 목록에서 "WPF" 를 선택하신 후 우측의 메뉴 리스트에서 WPF Application 메뉴를
선택합니다. 그리고 대화상자 맨 하단에 보시면 프로그래밍 하실 언어를 설정하는 메뉴를 보실 수 있으실 겁니다.
언어를 보시면 C# 과 Visual Basic 두 가지의 언어가 있는데요,
저희 카페가 비주얼베이직 전문 카페인 만큼, Visual Basic 으로 설정해주세요~
이렇게 설정하셨으면 프로젝트 생성을 위한 설정은 모두 끝난겁니다. 아래 보이시는 것 처럼 OK 버튼을 눌러주세요.
아래는 Expression Blend 의 기본적인 메뉴 설명이에요.
우선 여기서는 가장 기본적인 프로그램 (인터넷 바로가기) 을 만들어 본 후 데코레이션 해 보도록 하겠습니다.
모두들 아시다시피 우선 버튼이 필요하겠죠?
버튼 컨트롤을 찾아 그림과 같이 폼(Form) 안에 집어 넣어줍니다.
그리고는 비주얼베이직을 실행 시키신 후 (물론 Expression Blend 프로그램은 열려 있는 상태이구요)
"Open Project" 기능을 이용하여 아까 파일을 저장했던 경로로 들어가신 후 .sln 확장자로 이루어진 (솔루션) 파일을 불러오시구 나서
아래와 같이 버튼에 표시되는 텍스트를 바꾸어주시구요.
참고로, WPF 의 경우 Button 속성에 Text 속성이 없는 대신 Content 라는 속성이 있으니 해당 속성을 이용하시면 버튼의 텍스트를
수정하실 수 있습니다.
그렇게 버튼의 Content 속성을 변경해주셨으면 아래 보이시는 것 처럼 코딩해주세요.
물론 특정 웹사이트로 이동하는 소스 코드입니다. ^^;;
코딩이 모두 끝나면 해당 프로젝트 파일을 저장하신 후 (단축키 : Ctrl + Shift + S)
최소화 되어 있던 Expression Blend를 최대화 시키시면 아래와 같은 메시지가 뜨는 것을 확인하실 수 있을 텐데요,
이 메시지는 외부에서 파일이 수정되었다는 것을 프로그램이 자동으로 인식하여 나오는 메시지입니다.
번역해보면
"이 파일은 외부에서 수정된 파일입니다.
수정된 파일을 로드하시겠습니까?" 라는군요..
여기서 "Yes" 를 누르셔서 재로드 하시면,
아래와 같이 버튼 내의 텍스트가 변경되는 것을 확인하실 수 있을 겁니다.
이번에는 Expression Blend 의 코딩 창을 확인해보았습니다.
(Expression Blend 에서두 역시 변경이 완료되었습니다 ㅎㅎ ^^;;)
이제 본격적으로 버튼을 꾸며 볼까요?
옆에 있는 Properties 속성에서 Background 속성을 이용하여 버튼을 아래와 같이 꾸며줍니다.
물론 보이는 Foreground 속성은 글자 색 설정을 위한 속성하라는 것 모두 알고 계시죠?
여기까지 모두 완료 되셨으면 이번에도 역시 파일을 저장 (단축키 : Ctrl + S) 합니다.
이제 최소화 되어 있던 비주얼베이직을 최대화 시키시면 아래와 같이 아까와 비슷한
"이 파일은 외부에서 수정된 파일입니다.
수정된 파일을 재로드 하시겠습니까?" 라는 메시지가 뜹니다.
이번에두 역시 Yes 버튼을 눌러 재로드 하세요
비주얼베이직의 경우 아래처럼 상단에 노란색 경고 바가 한번 더 뜨는데요,
겁먹으시지 마시구 역시 클릭하셔서 재로드 해 주시면 됩니다.
아까 편집한 버튼의 모양처럼 이렇게 멋있게 다시 등장했습니다.
이제 디버깅을 해 봅시다.
버튼이.. 뽀대나는 군뇨..
비주얼베이직의 개성없는 회색버튼 보다는 Expression Blend 에서 직접 디자인한 이 버튼이 확실히 좋군요,,, (우왕 굳~!!)
아래와 같이 버튼을 클릭하여 인터넷을 접속해보았습니다.. ^^;;
이렇게 Expression을 이용한 GUI 디자인이 완료되었습니다/
다른 컨트롤들도 같은 방법으로 디자인 하면 된답니다..~
마지막 특별 비교 스크린 샷!
위쪽이 비주얼베이직에서 디버깅된 창의 모습입니다.
아래는 Expression 제품 계열의 Expression Blend 에서 디버깅한 창의 모습이구요.. ㅋㅋ
오늘은 버튼을 디자인 하는 방법을 알아보았습니다~
그럼 이렇게 Expression Blend 를 이용한 첫 강좌의 막을 내리도록 하구요~
다음 강좌에는 또 다른 컨트롤들을 꾸며 보는 시간을 가져보도록 하겠습니다.
여기까지 읽어주셔서 감사합니다.
러브홀릭 iN 비주얼베이직 카페 매니저 화이트보노 씀.
최근 프로젝트로 인하여 별로 사용할 일이 없었던 WPF에 손을 대고 있습니다.
지금까지 사용했던 적이 없던 것이 아니지만.. Canvas를 이용해서 컨텐츠를 개발하는 정도가 고작이었던터라.. 나름대로 새롭게 공부할 필요를 느껴 서적을 들여다보니.. 아키텍처와 관련하여 아주 잘 정리된 내용이 있더군요. (검색을 통해서는 잘 알 수 없었던...)
언제나 느끼지만.. 플랫폼을 접할 때 그 플랫폼에서 개발을 어떻게 하는지만을 배울 것이 아니라.. 좀 더 근본적으로 그 플랫폼이 어떻게 생겨먹었는지 알아가는 것이 먼저라는 생각이 듭니다.
이런 이유로 WPF아키텍처에 대해서 제가 이해한 내용을 간단하게 포스팅합니다.
이번 포스팅에서는 기본적인 WPF Architecture를 비롯해 Dispatcher Object, Dependency Object에 대해서 다루어보고.. 다음 포스팅에서 Visual과 UIElement, Framework Element, Control등에 대해서 다루어 보겠습니다.
WPF Architecture
WPF는 닷넷 3.0과 함께 발표되었고, 2.0을 기반으로 3.0에 포함되었다.
WPF는 관리코드로 작성되고 노출되어 있으며, 아래 아키텍처 상에서 푸른색으로 표시된 부분이 핵심이라고 할 수 있다.
Presentation Framework와 PresentationCore는 순수한 관리 코드로 구성되있다.
개발자가 만나게 되는 WPF는 바로 이 부분이다. CLR 바로 위에 노출되어 있는 층이 Presentation Core부분인데 WPF를 위한 API부분을 주로 정의하는 부분이다.
우리가 Windows 클라이언트에서 UI를 프로그래밍 할 때 API와 Library 형태로 많은 것을 제공 받아왔다. WPF의 Core부분은 API형태Library, 컴포넌트 형태를 띠고 있다.
최상위 계층에 Presentation Framework를 배치하고 있는데 여러 WPF 핵심 기능을 조합해서 새로운 Framework를 만들어 제공하는 부분이다. WPF클래스를 읽을 때 Core부분과 Framework부분이 분리되어 있다는 것도 염두에 두어야 한다.
CLR계층 아래 milcore 계층은 DirectX와 효율적인 통신을 위해 비관리 코드로 제작된 부분이다. CLR 하부에 배치됨으로써 개발자에게 쉽게 접근을 허용하지 않는다. 개발자는 DirectX와 통신을 milcore 어셈블리에 미루면 된다. WPF에서의 모든 디스플레이는 DirectX엔진을 통해 수행되므로 효율적인 하드웨어 및 소프트웨어 렌더링을 허용한다. 관리 코드를 사용함으로써 효율적인 메모리 및 자원 관리도 가능하다. milcore는 성능을 위해 관리 코드의 이점을 포기한 부분이다.
WPF관련 어셈블리는 크세 세 부분으로 나눌 수 있다.
1. WindowBase.dll 2. PresentationCore.dll 3. PresentationFramework.dll
|
WindowsBase.dll은 WPF를 위한 기본 서비스를 제공하는 어셈블리로 Dispatcher 클래스와 DependencyObject 클래스를 포함한다. WPF 어플리케이션이 구동되기 위해서는 반드시 필요한 어셈블리라고 할 수 있다.
실제로 WPF 어플리케이션의 기본 프로젝트를 생성하면 언급한 어셈블리들이 참조되어 있는 것을 확인할 수 있다.
Dispatcher Object
닷넷에서 상속의 최상위 클래스라면 System.Object를 말한다. 하지만 WPF를 이야기할 때 대부분의 WPF객체들은 DispatcherObject에서 파생된다. System.Windows.Threading 네임스페이스에 DispatcherObject 클래스가 위치하게 된다. 네임스페이스가 System.Windows에서 시작되고 Threading 네임스페이스로 이어지는데 기존 닷넷 프레임워크 2.0에 있는 System.Threading과는 다른 네임스페이스이다. 언급한 네임스페이스는 그대로 유지되고있다. WPF가 새로운 Threading모델을 사용하고 관련 클래스를 정의한 네임스페이스가 System.Windows.Threading이다.
WPF는 STA(Single Thread Apartment) 모델과 호환되는 시스템이다. STA모델이란 실행 컨텍스트에 하나의 스레드만 존재하는 시스템을 말한다. STA모델에서 어플리케이션이 실행된다면 스레드에는 한 순간 하나의 객체만 존재하게 되므로 객체간에 서로 통신할 방법이 필요하게 된다.
WPF에서 Dispatcher는 복수의 작업을 대기시킬 수 있는 큐이다. Dispatcher의 또 하나의 중요한 기능은 접근 가능 여부를 확인시켜 주는 것이다. WPF는 어플리케이션이 시작될 때 UI 스레드와 렌더링 스레드를 포함해서 최소 두 개 이상의 스레드를 생성한다. 렌더링 스레드는 백그라운드에서 실행된다.
DispatcherObject는 WPF의 이러한 스레드 모델을 지원하는 객체이고 Dispatcher라는 속성을 갖는데 자신이 속한 스레드의 Dispatcher에 접근하기 위한 방법인 것이다. 그러므로 쉽게 스레드의 Dispatcher와 DispatcherObject의 Dispatcher가 동일한지 여부를 쉽게 비교할 수 있다. CheckAccess()와 VerifyAccess() 메서드가 그런 역할을 담당한다.
Dispatcher의 또 다른 중요한 기능 중의 하나는 Dispatcher에 Invoke()나 BeginInvoke()를 호출해 Frame을 Queueing할 수 있다. 같은 Dispatcher를 공유하지 않을 때 Invoke()나 BeginInvoke()를 이용해야 한다.
Dependency Object
Dependency Object는 WPF의 Property System 서비스를 가능하게 하는 객체이다. 바꾸어 말하면 Dependency Object는 WPF의 Property System에 의존하는 객체인 것이다.
또 다르게 말하면 개발자가 Dependency Object에서 파생만 한다면 WPF에서 관리를 한다는 뜻이기도 하다.
WPF는 메서드 이벤트 보다는 속성 중심으로 설계되어 있는데 객체의 멤버를 살펴볼 때 속성의 늘어난 숫자에 놀라게 된다. 데이터 중심, 모델 중심으로의 관전의 전환이라고 할 수 있다. 데이터 중심 프로그래밍을 설명할 때 코드를 데이터로 부터 분리하는 것을 의한다. 데이터 중심 프로그래밍에서 데이터는 단순히 상태 정보만을 의미하는 것은 아니다. 객체지향에서 Data는 캡슐화된 숨겨진 정보를 의미한다. 데이터 중심 프로그래밍에서 데이터는 프로그램에서 흐름 제어까지 포함한다. 데이터 중심 프로그래밍이란 코드에 의한 데이터 변경을 최소화하고 데이터 구조 중심의 프로그래밍을 하겠다는 것이다. 잘만 설계가 이루어지고 행해진다면 데이터 중심의 프로그래밍은 코드의 양이 적고 선언적인 형태를 보이게 된다. 마이크로소프트의 XAML 관련 문서를 검토하다 보면 흐름 제어, 선언적이라는 단어를 만나게 된다. WPF가 디자인과 통합 유지 관리의 편의성 등을 위한 선택일 것이다. XAML에서는 이벤트와 액션까지 모델화하고 선언적으로 처리하는 것을 볼 수 있다. 제어의 많은 부분을 바인딩을 통해 가능하게 되었다.
WPF 속성 시스템은 속성 식 간의 종속성을 추적하고 종속성이 변경될 때 속성 값의 유효성을 자동으로 다시 검사하는 면에서 진정한 '종속성' 속성 시스템이라고 할 수 있다. WPF가 지원하는 형태의 속성을 Dependency Property라고 하는데 양방향 변경 알림과 추적이 가능하다. 부모에서 상속된 속성이 있을 경우 부모에서 변경이 된다면 자식에게 영향을 미치고 반대의 경우에도 마찬가지이다. 객체 지향의 관점에서 본다면 별개의 인스턴스가 되므로 서로 영향을 미칠 수 없지만 WPF의 속성에서는 가능한데 이는 클래스 수준의 속성 관리와 별개의 관리 시스템에 인스턴스가 등록되고 관리되기 때문에 가능하다. WPF에서 많은 속성은 정적이고 선언과 동시에 등록이 이루어진다.
앞에서 WPF는 데이터 중심, 속성 중심의 양방향 알림 공지가 가능한 시스템이라고 설명했는데 한 걸음 더 나가 속성 시스템은 프레임워크 수준의 바인딩 스타일 등을 지원한다. 프레임워크 수준에서 지원하므로 객체 수준의 하드 코딩된 바인딩이나 스타일 등은 권장하지 않는다는 것이다. 프레임워크의 정점에 있는 객체가 Dependency Object이다. 바인딩 스타일 등은 바인식 식(Expression)에 의해 지원되는데 사용자가 마음대로 변경할 수 없는 패쇄된 시스템이다. 정해진 방법과 키워드를 통해 바인딩 스타일 등을 지정해야 하는 엄격함을 지니고 있다. 이는 선언적 머크업과 호환 가능한 시스템을 구현해야 하므로 XML의 엄격함을 수용했을 것이다.
프레임워크 수준의 바인딩 종속성, 손쉬운 데이터 공유 등의 기능은 속성의 값을 모든 객체의 인스턴스에 저장하지 않아도 가능하게 했다. 예로 시스템이 지원하는 폰트가 있다고 할 때 모든 인스턴스가 폰트의 클론 데이터를 유지할 필요는 없다. 폰트 변경에 대해 적절한 타이밍에 서로 알려 줄 수만 있다면 한곳에 저장해도 아무런 문제를 발생시키지 않는다. 가벼운 속성 시스템을 유지하는 것이 가능한 것이다. 기본 값이나 많은 인스턴스가 같은 값을 동시 참조할 때 성능 면에서 도움이 크다.
또 하나는 XAML에서 사용하는 연결된 속성이다. 역시 Dependency Object이어야만 지원 받을 수 있는 기능이다. 예를 들어 보면 흔히 말하는 DockingPanel이 있고, Button이 내부에 배치될 때 Button.Left 혹은 Button.Docking 정도의 속성으로 설계가 이루어 질 것이다. Button의 속성을 통해 이루어지는데 Docking 속성은 어떤 데이터 형을 가져야 하는 것일까? 난감하다..
Docking의 내용은 Button을 포함하는 객체의 Type에 따라 달라진다. 포함 객체가 어떤 기능을 제공하느냐에 따라 달라져야 한다. 이럴 경우 포함 객체는 Button에 의해 제약을 받거나 혹은 반대로 포함 객체가 Button을 제약하게 된다. 불필요한 Coupling이 발생하게 되는 것이다. 해결책은 포함 객체는 Docking에 관한 방법을 제공하고 포함되는 객체는 제공된 방법 중 선택을 해서 보고해야 한다. 이러한 부분을 WPF 프레임워크가 담당하게 된다. 연결 속성의 지원을 받으려면 Dependency Object이어여 한다.
다음 예는 Canvas라고 하는 포함 객체가 있고 Button이 여기에 포함된다. Canvas는 좌표 값을 통해 배치하는 것이 가능한 컨테이너이다. 여기에 좌표는 당연히 컨테이너가 정해준 방법에 따라 달라져야 할 것이다.
<Canvas> <Button Canvas.Left="100" Canvas.Top="100" Width="100" Height="50"> This is Button </Button> </Canvas>
|
이와 같은 예에서 WPF를 처음 접하면 난감한 부분이 Button의 Attribute중 Canvas.Left라고 하는 연결 속성이다. 배치는 Canvas가 책임지고 Button은 Canvas에게 보고를 하면 나머지는 이루어지는 것이다. 연결 속성은 다른 객체의 속성으로 사용이 가능한 것이다.
Dependency Object가 WPF 프레임워크 내에서 하는 역할을 알아보았는데 WPF의 속성 시스템의 지원을 받기 위해서는 Dependency Object에서 파생해야 한다는 것이다.
최근 프로젝트로 인하여 별로 사용할 일이 없었던 WPF에 손을 대고 있습니다.
지금까지 사용했던 적이 없던 것이 아니지만.. Canvas를 이용해서 컨텐츠를 개발하는 정도가 고작이었던터라.. 나름대로 새롭게 공부할 필요를 느껴 서적을 들여다보니.. 아키텍처와 관련하여 아주 잘 정리된 내용이 있더군요. (검색을 통해서는 잘 알 수 없었던...)
언제나 느끼지만.. 플랫폼을 접할 때 그 플랫폼에서 개발을 어떻게 하는지만을 배울 것이 아니라.. 좀 더 근본적으로 그 플랫폼이 어떻게 생겨먹었는지 알아가는 것이 먼저라는 생각이 듭니다.
이런 이유로 WPF아키텍처에 대해서 제가 이해한 내용을 간단하게 포스팅합니다.
이번 포스팅에서 Visual과 UIElement, Framework Element, Control등에 대해서 정리합니다.
WPF Architecture를 비롯해 Dispatcher Object, Dependency Object에 대해서는 이전 포스팅에서 다루었으니 참고하시면 되겠습니다. (http://blog.naver.com/silent1002/10083967513)
Visual
Visual 클래스는 렌더링을 담당하는 객체이며 컨트롤 클래스의 시작점이다. 렌더링이란 그리는 작업을 말하는데 WPF는 DirectX를 이용해 렌더링 한다. Visual 클래스는 렌더링을 담당하므로 milcore 컴포넌트와 닿아 있다.
Visual 클래스가 제공하는 기능을 알아보기 전에 WPF 시스템이 렌더링을 어떻게 구현하는지를 알아볼 필요가 있다. WPF는 3차원이 지원되고 해당 객체를 그릴 때 멀리 있는 것과 가까이 있는 것을 구별하여 그릴때 Painter's Algorithm을 사용하는데 멀리 있는 객체부터 먼저 그리고 가까이 있는 것을 그 위에 겹쳐 그리는 방법을 사용한다. 뒤에 있는 것은 가려져서 보이지는 않지만 객체는 온전한 상태로 유지되고 있는 것이다. 그려진 객체는 사용이 종료될 때까지 유지되고 캐시된다. 하지만 GDI에서는 클리핑 시스템을 사용한다. 그릴 부분을 미리 계산해서 잘라서 그리는 방법을 사용하낟. 최근의 그래픽 하드웨어들은 WPF가 사용하는 방법에서 더 효율적인 성능을 나타낸다고 한다.
이렇게 캐시되고 유지되는 렌더링 시스템에서는 모든 그리기 작업이 Visual 객체로 구현된다. GDI에서는 DrawLine()메서드를 호출해 라인을 그린다. 즉, 명령을 이용해 렌더링을 구현하고 있는 것이다.
protected overrid void OnPaint(PaintEventArgs e) { e.Graphics.DrawLine(Pens.Black, 10, 10, 100, 100); e.Graphics.DrawEllipse(Pens.Black, 10, 10, 100, 100);
base.OnPaint(e); }
|
GDI+를 이용한 선과 타원을 그리는 작업이다. Graphics객체를 이용해 렌더링할 표면에 그리고 있는데 단순한 벡터로 그려지고 있는 것을 볼 수 있다. 위의 예제에서 만약 사용자가 10, 10을 마우스로 클릭하면 Line을 클릭한 것일까 타원을 클릭한 것일까..? 바보 같은 질문이지만 Line도 타원도 아니다. GDI+에서 Line이나 Ellipse는 적중 테스트의 대상이 되지를 못한다. 구별하는 것은 개발자의 몫이다.
WPF에서는 Line을 그리려면 GDI+와는 방법을 달리해야 한다. 이것을 이해하고 느끼는 것은 앞서 언급한 유지된 렌더링 시스템을 이해하는 데 도움이 될 것이다. Line하나를 코드로 선언한다면 다음과 같은 코드를 사용해야 하는데 Line 객체는 Visual에서 상속된 객체이다. Visual 클래스가 제공하는 서비스를 온전히 받을 수 있는 것이다. 이제 Line객체가 마우스의 클릭 이벤트를 받을 수 있느냐는 그리고 고민할 문제가 못된다. Line객체가 그런 기능을 가지고 있느냐 없느냐의 문제를 따져 보면 된다. 예제를 서로 비교해 보면 알 수 있듯이 WPF 시스템이 보다 데이터 중심 프로그래밍으로 옮겨 가고 있음을 알 수 있다.
private void AddShape() { Line myLine = new Line(); myLine.Stroke = Brushes.Black; myLine.X1 = 1; myLine.X2 = 50; myLine.Y1 = 1; myLine.Y2 = 50; myLine.StrokeThickness = 2;
myGrid.Children.Add(myLine); }
|
이제 Visual 클래스가 가진 주요 기능을 살펴보면 되는데 다음과 같다.
- 출력표시 : 유지 및 Serialize된 Visual Element의 그리기 내용을 렌더링 한다.
- 변환 : Visual Element에 대한 변환을 수행한다.
- 클리핑 : Visual Element에 대한 클리핑 영역 지원을 제공하낟.
- 적중 테스트 : 지정된 좌표 또는 기하 도형이 시각적 요소의 경계 내에 포함되어 있는지 여부를 확인한다.
- 경계 상자 계산 : Visual Element의 경계 사각형을 확인한다.
Visual 클래스는 렌더링과 관련된 변환이나 경계 상자 즉, 슬롯에 관련되는 계산은 책임지지만 입출력 부분이나 이벤트 레이아웃 등은 다루지 않는다.
UIElement
UIElement는 PresentationCore 부분에서 하위 부분에 구현되어 있고 레이아웃, 입력 및 이벤트 등의 핵심 기능을 담당한다. Windows 개발자들이 오랫동안 익숙한 레이아웃은 절대 좌표 기반의 레이아웃으로 Button.Left=100 Button.Width=200과 같은 형태로 레이아웃을 정의하는 방법이다. 하지만 html에서는 Flowlayout도 지원하고 Table을 이용한 레이아웃 방법도 잇다. 그런데 절대좌표를 이용한 배치 방법은 하드웨어가 달라지거나 할 때 곤란한 일이 발생한다.
레이아웃은 디자인 관점에서 중요한 요소이다. 디자인 산출물은 XAML을 이용해 남겨지는 것이 가장 편리한 방법이고 보면 레이아웃은 선언적인 방법으로 사용이 가능해야 한다. 또 하나는 레이아웃을 사용자가 고유하게 정의할 수 있어야 유연한 시스템이 될 것이다.
WPF의 UIElement는 레이아웃을 정의하기 위해 두 가지 기본 개념 우너칙을 제시한다.
Measure와 Arrange인데 크기를 정의하기 위해서는 Measure라는 개념을..
위치와 정렬을 위해서는 Arrange라는 개념을 적용한다.
WPF에서 이것을 2단계 레이아웃이라 명명하고 있다. 레이아웃을 포함하는 객체가 포함 객체와 통신해 레이아웃을 결정한다.
WPF의 입력 시스템을 거쳐 발생한 이벤트는 라우트된 이벤트라고 하는데 이벤트 트리 경로의 위쪽 루트로 전달되는 버블링 이벤트와 라우트된 이벤트라고 하는데 이벤트 트리 경로의 위쪽 루트로 전달되는 버블링 이벤트와 루트에서 해당 객체로 반대로 전달되는 터널링 이벤트를 모두 지원한다. UIElement는 자신 자체만으로 이벤트를 수신하는 것이 가능한 것이다.
이를 좀더 발전시켜 Command와 입력 제스처, Command Binding이라는 개념으로 추상화 시킨다. 수행해야 할 명령을 추상화시켜 Command라 하고 입력을 객체화 시켜 입력 제스처로 정의된다. 수행해야 할 명령을 추상화시켜 Command라 하고 입력을 객체화 시켜 입력 제스처로 정의한다. 입력과 Command가 분리되는 것이다. 이제 입력은 더 이상 공유해서 함게 사용하는 값이 아니고 자유롭게 정의할 수 있는 선언적인 객체인 것이다. UIElement는 Command bindings라는 속성을 가지고 있는데 Command binding을 여러 개 저장하겠다는 의미이다. 변개로 정의된 Command와 입력 제스처를 묶어서 Command Binding이라 하고 이를 관리하겠다는 의미이다.
Framework Element
Framework Element는 WPF 프레임워크 수준 요소 클래스와 UI Element 프레젠테이션 서비스의 WPF 핵심 수준 집합을 연결해 주는 지점 역할을 한다.
Framework 클래스의 중요한 기능으로 다음과 같은 기능을 제공한다.
- 레이아웃 시스템 정의
Framework Element에서는 UI Element에서 가상 멤버로 정의된 특정 메서드에 대해 특정 WPF프레임워크 수준 구현을 제공한다. 특히, Framework Element는 특정 WPF 핵심 수준 레이아웃 재정의를 봉인하며 대신 파생 클래스가 재정의 해야하는 해당 WPF프레임워크 수준 레이아웃 재정의를 제공한다. 예를 들어 Framework Element는 Arrange Core를 봉인하지만 Arrange Override를 제공한다. 이는 Framework Element수준에서 핵심 기능의 손상 없이 새로운 레이아웃을 정의할 수 있는 방법을 제공한다는 뜻이다.
- 논리적 트리
요소 트리를 논리적 트리로 표현하고 태그에서 이러한 트리를 정의하는 작업은 Framework Element 수준에서 구현된다. WPF에서는 트리를 이용해 구조를 정의하는데 논리 트리는 Visual 트리와는 다른 개념으로 마크업을 이용해 구조를 표현할 때 사용된다. 논리적 트리는 Framework Element에서 부터 정의가 가능하다.
- 객체 수명 이벤트
Windows 프로그래밍 시에 익숙해진 것 중에 하나가 객체들이 생성/소멸되는 수명에 관한 문제이다. Load()에서 변수나 객체를 무심코 초기화하곤 했다. WPF 프로그래밍에서 처음 접하는 것이 XAML파일이고 XAML에 표현된 논리적 트리이다. 생성되는 순서와 메모리에 로딩되는 순서가 어디에 정의해야 하느냐에 문제가 따르는데 WPF는 직관적 인식 단위인 논리적 트리를 포함하기 시작하는 Framework Element에 정의한다. 수명 사이클은 단순한 편이어서 Initialized, Loaded, Unloaded 세 가지를 지원한다.
- 데이터 바인딩 및 동적 리소스 참조 지원
데이터 바인딩 및 리소스에 대한 기본적인 수준의 지원은 Dependency Property 클래스에서 구현되며 속성 시스템에 포함되지만, WPF의 데이터 바인딩은 Framework 수준의 폐쇄된 구조를 가지고 있다. 즉, Framewok에서 지정한 방법으로 바인딩을 해야 하는 구조를 가지고 있다. WPF에서는 Expression을 이용해 바인딩을 하고 Framework는 이를 해석한다. 그렇게 함으로써 데이터 바인딩을 위한 하드 코딩을 지양하고 일관된 프로그램 패턴을 가능하게 한다. 또한 다양한 외부 리소스에 대한 동적 바인딩도 쉽게하는 이점이 있다. 중요한 기능으로 Framework Element는 자체 리소스를 관리할 수 잇는 컬렉션을 정의하고 있다.
- 스타일
Framework Element는 Style 속성을 정의한다. Style은 여러 개의 속성을 한 번에 적용하는 방법을 의미하는데 주로 컨트롤의 외관을 변형하기 위해 사용된다. 그러나 Framework Element는 템플릿 지워을 정의하거나 Decorator Content Model을 지원하지 않는다. WPF에서 Template은 주로 사용자가 Visual 트리를 재정의 하기 위해 사용하는 방법이다.
- 애니메이션 지원
WPF 핵심 수준에도 일부 애니메이션 지원이 이미 정의되어 있지만, Framework Element는 BeginStroyBoard 및 관련 멤버를 구현하여 이러한 지원을 확장한다.
Control
오랫동안 우리가 알고 있는 Control클래스를 시각적 요소를 갖는 컴포넌트라고 한다면 약간 개념의 정리가 필요할 듯하다. WPF 이전에 Control 클래스에서 상속된 객체들이 대체로 시각적 요소를 가졌다. 그래서 위의 Control에 대한 정의가 상당히 부합되는 면이 있다. 하지만 WPF에서는 Visual 클래스가 렌더링 역할을 책임지므로 이러한 개념은 문제를 드러낸다. WPF에서는 Control클래스에 대한 역할 정의를 분명히 해야 하는 이유가 여기에 있다. 렌더링이 Visual 객체의 역할이고 WPF Control 클래스의 역할은 Template 지원 기능이 가장 중요하다.
Control Template은 렌더링을 위해 선언 형식으로 대체가 가능한 스크립트이다. 풀어서 설명하면 XAML을 통해서 Template을 정의하면 WPF 프레임워크는 렌더링 시에 스크립트를 읽어 들여 반영하는 것이다. 결과적으로 Control 클래스는 Template을 통해서 렌더링 내용을 변경이 가능하다는 것이다. WPF 이전에는 Control UI를 변경하자면 렌더링 라이프 사이클 상에 있는 메서드를 오버라이드 하거나 컨트롤을 만들어 자식 요소로 추가해야했다. WPF에서는 Control의 중요한 기능으로 Template을 지원한다. UI를 변경하기 위해 먼저 고려해야 할 방법이 Template을 대체하는 것이다. 가장 편리하고 력한 방법이 될 것이다.
Control은 Framework의 강력한 지워을 받게 되었고 속성, 이벤트, Command 그리고 Template의 기능을 가지게 되었다. 속성은 데이터 모델이자 데이터 중심의 프로그램을 지원하겠다는 것이며 사용자의 상호 작용을 위해서 개선된 이벤트 모델과 Command 모델을 제시한다. 또한 시작적인 부분에서는 Template 기능을 통해 간편하고 강력한 기능을 지원한다.
최근 프로젝트로 인하여 별로 사용할 일이 없었던 WPF에 손을 대고 있습니다.
지금까지 사용했던 적이 없던 것이 아니지만.. Canvas를 이용해서 컨텐츠를 개발하는 정도가 고작이었던터라.. 나름대로 새롭게 공부할 필요를 느껴 서적을 들여다보니.. 아키텍처와 관련하여 아주 잘 정리된 내용이 있더군요. (검색을 통해서는 잘 알 수 없었던...)
언제나 느끼지만.. 플랫폼을 접할 때 그 플랫폼에서 개발을 어떻게 하는지만을 배울 것이 아니라.. 좀 더 근본적으로 그 플랫폼이 어떻게 생겨먹었는지 알아가는 것이 먼저라는 생각이 듭니다.
이런 이유로 WPF아키텍처에 대해서 제가 이해한 내용을 간단하게 포스팅합니다.
이번 포스팅에서 실제로 WPF 구조 이해에 도움이 될만한 간단한 실습(?)을 해볼 것입니다.
매우 간단하므로.. 너무 많은 기대를 가지지는 마시길 바라며 글을 작성합니다. ^^
이전 글을 아직 읽어보지 않으신 분은 아래 두 개의 글을 먼저 읽어보면 많은 도움이 될 수 있습니다.
WPF Architecture를 비롯해 Dispatcher Object, Dependency Object에 대해서..
(http://blog.naver.com/silent1002/10083967513)
Visual과 UIElement, Framework Element, Control등에 대해서..
(http://blog.naver.com/silent1002/10083967248)
WPF 구조 이해에 필요한 간단한 실습
우선 간단하게 WPF프로젝트를 하나 생성합니다.
솔루션 탐색기로 이동해 참조 부분에서
PresentationCore, PresentationFramework, WindowsBase 어셈블리가 있는 것을 눈으로 직접 확인해보도록 합니다.
PresentationCore, PresentationFramework, WindowsBase 어셈블리
|
|
어셈블리 살펴보기
PresentationCore, PresentationFramework, WindowsBase 어셈블리를 더블클릭 혹은 마우스 우클릭을 통해서 객체 브라우저로 살펴보도록 합니다.
버튼등의 간단한 컨트롤을 상속받은 클래스를 하나 생성해보도록 합니다.
본 글에서는 MyButton이라는 이름의 버튼을 상속받은 클래스를 하나 생성하였습니다.
그리고 프로젝트에서 클래스 다이어그램을 생성해보도록 합니다.
클래스 다이어그램을 만들어 봅니다.
|
|
아래는 생성된 클래스 다이어그램은 아래와 같습니다.
생성된 클래스 다이어그램
|
|
여기서 MyButton 객체를 우클릭하여 기본 클래스를 표시해 보도록합니다.
여기서 직접 MyButton의 기본 클래스를 확인해보도록 합니다.
클래스 다이어그램으로 본 MyButton의 기본 클래스
|
|
그리고 Button 클래스의 속성창을 직접 확인해봅니다.
Button 클래스의 속성
|
|
전체 이름과 파일 이름 항목을 확인하고 Object Browser정보와 직접 비교해 보도록합니다.
다음 사항들에 대해서 동일한 내용을 직접 확인해보도록 합니다.
- Visual < UI Element < Framework Element 순으로 상속됨을 직접 확인해보고..
- Framework Element와 UI Element를 확장해 속성중에 Resources가 있는지 확인합니다.
- 또한 UI Element에는 Resources속성이 없으므로 자체 리소스를 UI Element 수준에서는 저장할 수 없다는 것 또한 확인해봅니다.
글의 서두에서 언급했던 것과 같이 매우 간단한 실습을 해보았지만.. WPF를 접한지 얼마 안되신 분들에게는 WPF구조를 이해하기에 많은 도움을 드릴 수 있을 것입니다.
글로 읽는 것과 실제로 가시화시켜 확인하는 것은 다르기 때문입니다.
또한.. 이번 포스팅에 이어서 XAML이라던지.. 종속성 속성 등 WPF기본적인 요소에 대해서 계속해서 포스팅해 나갈 생각입니다. WPF를 공부하시는 분들께 조금이나마 도움을 드릴 수 있기를 바랍니다.
계속해서 작성한다면.. Control을 제작한다거나.. Expression Blend등을 이용한 개발등에 대한 내용 또한 포스팅 할 수도 있을 것 같습니다. (이런 부분들은 제가 직접 해봤던 부분들이기 떄문에 경험담을 토대로..)
아무튼 WPF 카테고리는 이런식으로 채워 나가게 될 것 같습니다. ^^
|
|