제가 또 일 끝까지 안하고 새로 일 벌리는 걸 좋아하죠. (…후우…)

MSDN POPCON에 ‘공도의 실버라이트 하기 좋은 날’이란 동영상 시리즈를 연재하기로 했어요. 매주 목요일날 업데이트 예정이고요, 내용은 그야말로 자유. 피드백 많이 주세요 :D

그 대망의 시리즈 제 1편: http://blogs.msdn.com/popcon/archive/2009/07/02/s-1.aspx

소개가 참 간드러지게 나왔는데요, 제가 원래 그 모양이니 모…ㅎㅎ

아래는 기각당한 초안이에요. 사실 이쪽이 더 마음에 들어서 남겨놉니다.^^

한 몇 개월 전부터 실버라이튼지 뭔지 하는 게 자꾸 사람들이 얘기는 하는데,
그까이꺼 대애애~충 훑어보니 뭐 별 어려워 보이는 것도 없고 해서 한 번 해 보는데,
팀장님이 '너 뭐하냐?' 물어보니 나름 깝쭉대 보지만?
아뿔사! 이건 뭐 내가 뭘 하는 지 설명을 못하겠네...
하는 당신을 위한 초고농도압축액기스추출 동영상!
액기스만 모았습니다. 짧습니다. 효과 (아마도)확실합니다!
(※부작용 발생 시 가까운 개발자나 디자이너에게 하소연하시기 바랍니다.)

P.S. 
손발은 오글오글.

[+ 동영상 다운로드]

저작자 표시 동일 조건 변경 허락
신고
Posted by gongdo

살다보니 마이크로소프트가 이런 것도 하네요^^ 지금 MSDN 사이트에 가보시면 MIX로 단장한 페이지를 볼 수 있어요.
예를 들면 http://msdn.microsoft.com/en-us/library/system.windows.media.matrixtransform.aspx 이런곳…

저작자 표시 동일 조건 변경 허락
신고
Posted by gongdo
TAG MIX09, MSDN
후우... 몇 일간 일도 못하고 이게 무슨 캐삽질이여...
그놈의 샘X 하드에 물리 배드가 생기는 바람에 그간 작업했던 TFS의 피같은 Work Item들을 다 날렸습니다.
진짜 하늘 노래지네요. 그나마 소스 코드 최종본들은 각자의 PC에 남아 있어서 프로젝트 완수에는 큰 지장이 없을 것 같지만...

언제나 백업은 소 잃고 외양간 고치기.
다음엔 나아질까...

여튼 기왕 다시 까는 김에 마이크로소프트의 2008 삼총사가 모두 정식 릴리즈도 되었겠다 그간 TFS 설치엔 나름 노하우가 생겼겠다해서 과감하게 2008 삼총사로 TFS를 구축해봤어요. 바로...
  • Windows Server 2008 (with IIS7)
  • SQL Server 2008
  • Visual Studio Team Foundation Server 2008 SP1
  • Windows SharePoint Service 3.0 SP1
진짜 과감하다 못해 파격적이지 않습니까! 네!? 진짜 그랬다고요!

이게 TFS 설치는 정말 순조로웠어요. 이 전하고 다르게 http://go.microsoft.com/fwlink/?LinkId=79226 이 링크에서 받을 수 있는 TFS 설치 가이드 문서가 가리키는 순서대로만 설치하면 문제 없이 잘 깔려요.

한 방에 설치를 끝내고 정말 기분 좋게(그러나 남은 노가다에 난감하게) 기존 프로젝트 들을 새로 만들고 세팅을 하고 있는데...

An error has occurred during report processing. (rsProcessingAborted)
Query execution failed for dataset 'IterationParam'. (rsErrorExecutingCommand)
For more information about this error navigate to the report server on the local server machine, or enable remote errors

리포팅 서버에서 이런 에러가 떡!하고 나오더군요.

게다가 뒤에 붙어있는 도움말 링크를 클릭해보면...
미안하지만 아직 문서가 준비 안됐거든? 나중에 해볼려? 이딴 소리나 하고... 아오!!!

그래서 또 다시 MSDN 포럼의 바다로 다이브.
딥 다이브.
    답은 2005에서나 쓰이던 방법
아직도 다이브.
    답은 TFS 2008 Beta에서나 쓰이던 방법
언제까지나 다이브.

그렇게 몇 시간인가 헤매다 겨우 답을 찾았네요.

문제 핵심을 요약해 보자면 SQL Server에 대한 접근 권한 문제로 발생하는 건데요, TfsWarehouse라는 데이터 베이스에 접근할 때 SQL Server의 기본 사용자인 NetworkService 계정에 권한이 없었던거죠.
이게 버그인지 뭔지 모르겠고 어쨌든 TFS 설치가이드 문서만 믿고 가다가 뒤통수를 제대로 강타 당했죠.

또 한번.
다시 한번.

거의 반쯤 정신 나간 상태로 포스팅하는거라 자세한 정리는 못하겠고, 여튼 http://social.msdn.microsoft.com/forums/en-US/tfssetup/thread/6d1d89c6-d167-4e2c-85d6-8a2e330a1041/ 
여기에서 DeChrist 이 사람이 쓴 답글을 참고하면 대략 해결 책을 찾을 수 있을 거에요.
잊지말고 꼭 찾아보길 바래... ㅠ.ㅜ

저작자 표시 동일 조건 변경 허락
신고
Posted by gongdo

먼저 실버라이트를 하면서 항상 느끼는 건 정말이지 보안에 대해 편집증 적으로 철저하다는 점인데요. 물론 이게 실제 사용에서는 불편이 되겠지만 수 많은 보안 위협에 대해 효과적인 대응이 가능하다는 점에서 감수해야 할 것 같아요. 뭐 당연한 얘기지만 개방 플랫폼이 될 수록 보안적으로 민감한 리소스 접근은 제한이 더 걸릴 수밖에 없으니까요.

그런 점에서 이 문서도 쓸데 없으리만치 장황하게 접근 제약에 대해 명확한 표현을 사용하고 있는데요, 긴 문장 다 읽을 필요 없이 서두와 정리된 표를 참고하시는 게 좋을 것 같네요.


※ 이 문서는 MSDN의 URL Access Restrictions in Silverlight 2를 번역한 것으로 실버라이트2 베타2를 기준으로 합니다. 추후 변경사항이 있을 경우 업데이트 하겠지만 기본적으로 위의 문서를 참고하세요.

보안상의 이유로 실버라이트 버전 2 런타임은 System.Net 네임스페이스에 있는 WebClient와 Http 클래스들에서 사용되는 URL의 접근을 제한합니다. 비슷한 접근 제약이 실버라이트 2 런타임에 의해  System.Windows.Controls 네임스페이스에 있는 ImageMediaElement 클래스를 포함하는 다른 클래스들에도 적용됩니다. 실버라이트 2 런타임은 또한 XAML 소스 파일과 URL의 클래스에 기반한 폰트 파일에도 접근 제약을 적용합니다.

커넥션은 크로스-존, 크로스-도메인 및 크로스-스키마 URL에 접근할 때 적용받습니다. 이 제약들은 네트워킹의 위협(예를 들어, 인터넷 서버에서 실행된 실버라이트 2 기반 애플리케이션이 로컬 인트라넷에 있는 리소스에 접근하는 위협 등)을 막기위해 디자인 되었습니다.

일반적인 URL 클래스들은 다음과 같습니다.

  • 크로스-스키마Cross-scheme URL : 한 스키마(예를 들어 HTTP)를 사용하여 어떤 웹 서버에 있는 한 HTML 페이지로부터 다운로드 된 실버라이트 2 애플리케이션이 같은 서버 혹은 다른 서버에 있는 리소스를 다른 스키마(예를 들어 HTTPS)를 사용하여 접근을 시도할 때.
  • 크로스-도메인Cross-domain URL : 어떤 웹 서버에서 다운로드 된 실버라이트 2 애플리케이션이 다른 타겟 서버에 있는 리소스에 접근(예를 들어 www.gongdosoft.com에 호스트된 애플리케이션이 www.gongdosoft.net에 있는 컨텐츠에 접근을 시도하는 경우)을 시도할 때. 실버라이트 2 런타임은 일반적으로 타겟 서버로부터 이 접근을 허용할지를 결정하는 보안 정책 파일을 다운로드 하여 사용합니다.
Note:
실버라이트 2상에서 크로스 도메인 리소스를 접근할 수 있습니다. 그러나 보안 정책 파일에 명시적으로 활성화 할 필요가 있습니다. 자세한 정보는 실버라이트 2에서의 네트워크 보안 접근 제약 토픽을 보세요.

  • 크로스-존Cross-zone URL : 인터넷 익스플로러는 각각의 영역zone에 적용되는 보안 레벨을 가진 보안의 컨셉을 정의합니다. 여기에는 인터넷, 로컬 인트라넷, 신뢰된 사이트, 제한된 사이트의 네 영역이 정의되어 있습니다. 거기에 더해 로컬 머신은 또 다른 영역으로 고려됩니다. 크로스-존 URL은 어떤 보안 영역에 있는 웹 서버로부터 다운로드 된 실버라이트 애플리케이션이 다른 보안 영역에 있는 타겟 서버에 있는 리소스에 접근을 시도하는 경우를 말합니다. 크로스-존 접근 제약은 인터넷 영역에 있는 서버로부터 다운로드 된 실버라이트 2 애플리케이션이 더 신뢰할 수 있는 로컬 인트라넷이나 신뢰된 영역 및 로컬 머신 영역에 있는 리소스에 접근하는 것으로부터 보호하기 위해 디자인 되었습니다. 이것은 원격 인터넷 서버에서 실행된 실버라이트 2 애플리케이션이 로컬 인트라넷과 다른 리소스에 접근하는 것으로부터 보호를 말합니다. 크로스-존 접근은 타겟 서버에 접근이 허용된 리소스일지라도 막힙니다. 크로스-존 접근은 로컬 인트라넷 영역에 있는 서버에서 다운로드 된 애플리케이션이 인터넷 서버에 있는 리소스에 접근할 때에는 제약받지 않는 다는 점에 주의하세요. 그러나 모든 크로스-도메인 접근이든지 보안 정책 파일을 필요로 합니다. 크로스-존 접근 제약은 윈도우(OS) 상에서 실행된 실버라이트 2 애플리케이션에만 구현되어 있습니다. 보안 영역과 크로스-존 접근의 컨셉은 Apple의 OS X에서 실행된 실버라이트 2 애플리케이션에서는 아직 지원되지 않습니다.

다음 표는 WebClient와 HTTP 클래스들에 사용되는 URL 접근 제약과 다른 실버라이트 클래스 및 컴포넌트에서의 제약들을 포함한 규칙을 정리합니다.

 
WebClient HTTP 클래스 Image 클래스, 프로그레시브 다운로드 MediaElement 클래스(media, images, images, ASX, etc. XAML 소스 파일 폰트 파일 미디어 스트리밍
허용된 스키마 HTTP, HTTPS HTTP, HTTPS, FILE HTTP, HTTPS, FILE HTTP, HTTPS, FILE HTTP
크로스-스키마 접근 허용되지 않음 허용되지 않음 허용되지 않음 안됨 HTTPS에서는 허용되지 않음
크로스-도메인 접근 보안 정책 파일 필요. HTTPS에서 HTTPS라면 허용되지 않음. HTTPS에서 HTTPS 아닐 경우 허용. HTTPS에서 HTTPS 아닐 경우 허용. 허용되지 않음 HTTPS에서 HTTPS 아닐 경우 허용.
크로스- 접근(Windows) 인터넷 영역에서 제한된 영역으로의 접근은 허용되지 않음.
재전송Redirection 허용 여부 같은 사이트와 스키마로는 허용.
크로스-도메인은 보안 정책 파일이 있을 경우만 허용.
같은 스키마일 경우 허용. 허용되지 않음 허용되지 않음 허용되지 않음

Note:
사용자가 이 접근 정책들 중 하나의 위반으로 인한 에러 결과를 받은 경우 에러는 정확한 이유를 가리키지 않습니다.

만약 어떤 웹 서버에 호스트 된 실버라이트 2 애플리케이션을 가지고 있고 WebClient나 HTTP 클래스를 사용하여 이 애플리케이션에서 다른 웹 서버(크로스-도메인 URL)에 저장된 리소스로 접근을 시도하면, 다른 서버가 해당 접근을 명시적으로 허용하도록 만들어진 보안 정책 파일이 없는 한 그 요청은 실패할 것입니다. 윈도우(OS)상에서 만약 인터넷 영역에서 다운로드 된 실버라이트 2 애플리케이션이 보다 제한된 영역(로컬 인트라넷, 신뢰된 사이트 혹은 로컬 머신)에 있는 사이트 URL을 요청할 경우 심지어 가능하도록 된 보안 정책이 있다고 해도 실패할 것입니다. 또한 HTTP 스키마를 사용한 사이트에서 다운로드 된 실버라이트 2 애플리케이션이 HTTP 스키마를 사용하는 타겟 크로스-도메인 사이트를 요청할 경우에도 실패할 것입니다. 또한 HTTPS 스키마를 사용한 사이트에서 다운로드 된 실버라이트 2 애플리케이션이 HTTP 스키마를 사용하는 타겟 크로스-도메인 사이트를 요청할 경우에도 실패할 것입니다.

※ 너무 하나마나 한 소리라 아래의 제약 예제는 생략했습니다.

참조
신고
Posted by gongdo

2008/03/07 - [프로그래밍/Silverlight] - [Silverlight/MSDN] URL Access Policy
와 관련하여, 크로스 도메인 문제를 해결하기 위해 해당 서버에 접근 정책을 설정하는 방법에 대해 설명한 글이에요. 자세한 것은 원문을 보시고 여기에서는 HOW TO 부분만 가져왔습니다.

원문 : How to: Make a Service Available Across Domain Boundaries


실버라이트는 크로스 도메인 접근에 두 가지 매커니즘을 지원합니다.

  • clientaccesspolicy.xml
    ; 크로스 도메인 접근cross-domain-access하기 위한 서비스를 설정하기 위해 도메인의 루트에 놓는 파일.
  • crossdomain.xml
    ; 서비스가 호스트된 도메인의 루트에 놓는 파일. 파일은 반드시 공개할 도메인을 기록해야 합니다. 플래시에서 사용했던 방식으로 실버라이트도 이 스키마의 서브셋을 지원합니다.

clientaccesspolicy.xml 파일을 사용하여 크로스 도메인 접근하기

1. 실버라이트 클라이언트가 접근 가능한 서비스를 만듭니다. 자세한 정보는 실버라이트 클라이언트를 위한 서비스 만들기를 보세요.

2. 서비스에 접근을 허용하기 위해 clientaccesspolicy.xml 파일을 생성합니다. 다음 설정은 다른 어떤 도메인에서도 현재 도메인에 있는 모든 리소스를 접근하도록 허용합니다.

<?xml version="1.0" encoding="utf-8"?>
<access-policy>
    <cross-domain-access>
        <policy>
            <allow-from>
                <domain uri="*"/>
            </allow-from>
            <grant-to>
                <resource path="/" include-subpaths="true"/>
            </grant-to>
        </policy>
    </cross-domain-access>
</access-policy>

3. clientaccesspolicy.xml 파일을 서비스가 호스트되고 있는 도메인의 루트에 저장합니다. 예를 들어, http://fabrikam.com 에서 호스트되고 있는 서비스라면 반드시 http://fabrikam.com/clientaccesspolicy.xml에 위치해야 합니다.

4. 반면, http://contoso.com과 같은 딱 하나의 도메인에서만 접근을 허용하길 원한다면 clientaccesspolicy.xml은 다음과 같은 설정을 포함해야 합니다.

<access-policy>
    <cross-domain-access>
        <policy>
            <allow-from>
                <domain uri="http://contoso.com" />
            </allow-from>
            <grant-to>
                <resource path="/" include-subpaths="true"/>
            </grant-to>
        </policy>
    </cross-domain-access>
</access-policy>

5. 다른 도메인에서 서비스를 호출했을 때 접근이 가능한지 테스트합니다.


crossdomain.xml 파일을 사용하여 크로스 도메인 접근하기

1. 실버라이트 클라이언트에서 접근이 가능한 서비스를 만듭니다.

2. 다음 설정을 포함하는 crossdomain.xml 파일을 생성합니다. 파일은 반드시 다른 어떤 도메인에서도 서비스에 접근할 수 있도록 설정해야 하며 그렇지 않을 경우 실버라이트가 해석할 수 없습니다.

<?xml version="1.0"?>
<!DOCTYPE cross-domain-policy SYSTEM "http://www.macromedia.com/xml/dtds/cross-domain-policy.dtd">
<cross-domain-policy>
    <allow-access-from domain="*" />
</cross-domain-policy>

3. 서비스가 호스트된 도메인의 루트에 crossdomain.xml 파일을 서비스가 호스트되고 있는 도메인의 루트에 저장합니다. 예를 들어, http://fabrikam.com 에서 호스트되고 있는 서비스라면 반드시 http://fabrikam.com/crossdomain.xml에 위치해야 합니다.

4. 다른 도메인에서 서비스를 호출했을 때 접근이 가능한지 테스트합니다.

신고
Posted by gongdo

※ 이 문서는 실버라이트 2 Beta 1에만 해당하는 내용으로 Beta 2에서는 다음의 글로 대체 되었습니다. 이용에 착오 없으시길.

2008/06/28 - [프로그래밍/Silverlight] - [MSDN] URL 접근 제약

실버라이트 2에서 가장 크게 바뀐 점 중 하나는 URL 접근에 대한 정책이 기본적인 보안에 대해 안전하면서도 보다 구체적이고 융통성있도록 구성되었다는 점이죠. 특히 실버라이트를 테스트할 때에는 잘 되다가 게시했을 때 안되는 문제의 많은 부분이 바로 URL 접근과 관련하여 일어나는데요, MSDN에 명확하게 정리된 문서가 있어서 번역해봤어요.

원본 : http://msdn2.microsoft.com/en-us/library/cc189008(vs.95).aspx


보안 문제 때문에 마이크로소프트 실버라이트는 쿠키 전달이나 재전송redirection 허용과 같은 보안에 위협이 될만한 것들에 대한 크로스 존Cross-zone, 크로스 도메인, 크로스 스키마 URL 접근을 제한합니다. 예를 들어, 한 웹 도메인에 호스팅된 실버라이트 기반의 애플리케이션을 가지고 있고 WebClient 개체를 사용하여 다른 도메인에 저장되어 있는 파일에 접근을 시도한다면 그 요청은 실패할 것입니다. 다음 테이블에서 이러한 룰을 정리합니다.

Note:
실버라이트로 다른 도메인의 파일을 접근할 수도 있습니다. 그렇게 하기 위해서는 이 기능을 명시적으로 활성화할 필요가 있습니다. 보다 자세한 정보는 여기를 클릭하세요.

  WebClient object Media, images, ASX XAML files, Font files Streaming media
허용된 스키마 HTTP, HTTPS HTTP, HTTPS, FILE HTTP, HTTPS, FILE HTTP
크로스 스키마 접근 No No No HTTPS로부터는 안됨
크로스 웹 도메인 접근 No HTTPS가 아닐 경우 Yes No Yes
크로스 존 접근(Windows에서) No No No No
크로스 존 접근(Macintosh에서) No Yes No Yes
재전송 허용 같은 도메인에서 Yes 같은 도메인에서 No

Note:
이러한 접근 정책의 위반으로 인한 결과로 발생한 에러가 있을 때 그 에러는 아마도 정확한 이유를 가리키지 않을 것입니다.

앞에서 본 표에서 사용된 몇몇 용어의 정의는 다음과 같습니다.

  • 크로스 스키마Cross-scheme : 어떤 스키마(예를 들어 HTTP, HTTPS)에서 다른 스키마를 접근하는 것.
  • 크로스 웹 도메인Cross-Web domain : 어떤 웹 도메인과 다른 웹 도메인 사이의 접근(예를 들어 www.contoso.com에 호스팅된 애플리케이션이 www.fabrikam.com에 있는 콘텐트에 대한 접근을 시도).
  • 크로스 존Cross-zone : 보안 영역간의 접근. 예를 들어 인터넷 서버에서 인트라넷 리소스에 접근을 시도하는 것.

예를 들어, 애플리케이션을 호스트하고 이미지를 다른 서버에서 가져오고 싶다면 앞에서 본 표에 있는 "Media, images, ASX" 항목을 체크해볼 수 있습니다.

  • 만약 애플리케이션이 HTTP 사이트에 호스팅된다면 HTTPS 스키마를 사용한 사이트에서 이미지를 가져올 수 없습니다.
  • 그 도메인의 스키마가 HTTPS가 아닌 한 다른 도메인에서 이미지를 가져올 수 있습니다.
  • 만약 애플리케이션이 인터넷에 있고 사용자가 Mac을 사용하지 않는다면 이미지를 인트라넷에서 가져올 수 없습니다.
  • URL이 같은 도메인에 있는 한 다른 이미지 URL로 재전송할 수 있습니다.

참고

컨셉
미디어 포맷 및 프로토콜 지원(실버라이트 2)
코어 프리젠테이션 프레임워크 / UI

신고
Posted by gongdo

항상 새로운 기술을 접할 때에는 그 기술에 대한 전반적인 아키텍처와 구성, 특히 Overview를 읽어보는 것이 많은 도움이 되는 것 같아요. 저도 오랫만에 WPF스타일을 접해서 많은 혼란을 겪고 있어서 생각도 정리할 겸 MSDN 토픽 하나를 날림 번역해봤어요.

원본 글 : http://msdn2.microsoft.com/en-us/library/cc221365(vs.95).aspx

실버라이트는 애플리케이션 개발자에게 브라우저에서 실행되는 웹 애플리케이션을 개발하고 배포할 수 있게 하는 기술입니다. 이 토픽은 실버라이트 애플리케이션의 개발, 실버라이트 애플리케이션 및 라이브러리 어셈블리의 구현, 리소스 파일의 조직, 애플리케이션 서비스의 사용, 그리고 실버라이트가 제공하는 유연한 패키징 옵션을 다양한 개발 시나리오에 공급하는 것에 대한 개요를 제공합니다. 이 토픽은 클라이언트 측 캐싱에 관한 간단한 논의로 마무리합니다.

이 토픽은 다음과 같은 섹션을 포함합니다.

  • 애플리케이션 클래스, 어셈블리 및 패키지
  • 라이브러리 어셈블리
  • 리소스 파일
  • 패키지에 포함 vs 필요할 때 요청
  • 애플리케이션 서비스
  • 실버라이트 애플리케이션
  • 관련 토픽

실버라이트 애플리케이션에 관련된 정보는 Deployment (Silverlight 2)를 보세요.


애플리케이션 클래스, 어셈블리 및 패키지

각 실버라이트 애플리케이션은 반드시 실버라이트 플러그인 컨트롤에 의해 다운로드 된 이후 구동start up시키기 위한 최소한의 기능이라도 구현해야만 합니다. 만약 각 실버라이트 애플리케이션이 구동 기능을 각자의 방법으로 구현했다면 실버라이트 플러그인 컨트롤이 가능한 모든 구현을 공급하는 것은 불가능할 것입니다. 실버라이트 플러그인 컨트롤은 각 실버라이트 애플리케이션이 엔트리 포인트entry point라고 하는 잘 알려진 방법을 명시적으로 구동 기능을 구현하기를 기대합니다. 실버라이트 애플리케이션에서 엔트리 포인트는 다음의 항목들의 조합이 됩니다.

  • 애플리케이션 클래스application class라고 하는 Application에서 파생된 클래스.
  • 애플리케이션 어셈블리application assembly라고 하는 이 클래스를 구현하는 어셈블리.
  • 애플리케이션 클래스와 엔트리 포인트를 이루는 애플리케이션 어셈블리를 식별하는 메타 데이터.

최소한의 실행 가능한 실버라이트 애플리케이션은 애플리케이션 어셈블리(애플리케이션 클래스를 가지는)와 엔트리 포인트 메타데이터 모두를 포함하는 .xap 파일 확장자로 압축된 ZIP 파일입니다. .xap 파일은 애플리케이션 패키지로 알려져 있고 실버라이트 플러그인 컨트롤이 다운로드하고 실행하는 파일입니다.

애플리케이션 클래스와 애플리케이션 어셈블리를 어떻게 구현하고 패키지에 대한 자세한 정보는 Developing a Silverlight Application Assembly를 보세요.


라이브러리 어셈블리

애플리케이션 어셈블리가 일반적으로 실버라이트 애플리케이션의 메인 UI와 기능을 이루고 통합하는 반면, 라이브러리 어셈블리library assembly는 추가적인 애플리케이션 UI와 기능을 캡슐화할 수 있습니다. 라이브러리 어셈블리들은 애플리케이션을 더 쪼개진 요소로 분해하여 복잡도를 낮추고 다수의 애플리케이션에 걸쳐 UI와 기능을 공유하는 등의 다양한 이유로 사용됩니다.

실버라이트 라이브러리 어셈블리에 대한 자세한 정보는 Developing a Silverlight Library Assembly를 보세요.


리소스 파일

애플리케이션과 라이브러리 어셈블리가 실버라이트 애플리케이션의 실행가능한 형태를 캡슐화하는 한편, 실버라이트 애플리케이션은 오디오, 비디오, 이미지, XML 및 XAML 파일과 같은 비실행 데이터를 포함할 수도 있습니다. 이런 유형의 파일들은 집합적인 리소스 파일로 알려져 있고 다양한 방법으로 패키징될 수 있습니다.

리소스 파일의 작동에 대한 자세한 정보는 Application Services를 보세요.


패키지에 포함 vs 필요할 때 요청

실버라이트 애플리케이션은 하나의 애플리케이션 어셈블리, 0개 혹은 한개 이상의 라이브러리 어셈블리 및 0개 혹은 한개 이상의 리소스 파일의 덩어리입니다. 이 다양한 파일들이 어떻게 패키지되느냐는 가장 짧은 시간 동안 유저에게 올바른 기능을 제공하는 것의 평가에 달려있습니다.

앞서 얘기한 것처럼, 실버라이트 애플리케이션은 반드시 애플리케이션 클래스를 구현하는 애플리케이션 어셈블리를 가진 애플리케이션 패키지를 포함해야 합니다. 추가적으로 애플리케이션 패키지는 라이브러리 어셈블리와 리소스 파일을 포함할 수 있습니다. 애플리케이션 패키지는 실버라이트 애플리케이션을 시작하기 위해 실버라이트 플러그인 컨트롤이 다운로드하기 때문에 애플리케이션 패키지는 가급적 빠르게 다운로드 될 수 있도록 가능한 작아야 합니다. 따라서 애플리케이션의 UI와 기능을 구성하여 그것 없이는 애플리케이션의 실행이 불가능한 파일들만이 포함되어야 합니다. 예를 들어, 스프레드시트 애플리케이션과 같이 데이터를 입력하고 보여주는 기능만을 요구하는 애플리케이션을 생각해 봅시다. 애플리케이션 패키지에 포함되어 있는, 애플리케이션 어셈블리와 라이브러리 어셈블리와 리소스 파일을 포함하는 파일들이 바로 패키지에 포함된in-package 파일을 말합니다.

스프레드시트 애플리케이션은 또한 바 차트나 파이 차트처럼 언제나 사용되지는 않는 다른 데이터 뷰를 제공할 것입니다. 실버라이트 애플리케이션의 관점에 의하면, 애플리케이션의 선택적인 UI와 기능을 구성하는 파일들은 필요할 때 다운로드 될 수 있고 이것이 필요할 때 요청on-demand되는 파일입니다.

올바르게 구성된 스프레드는 사용자들이 애플리케이션 UI와 기능에 필요한 최소한의 초기 다운로드 비용이 들도록 하고 그들이 선택적인 기능을 원할 때만 추가적인 다운로드 비용이 들도록 합니다.

패키지에 포함하거나 필요할 때 요청되는 라이브러리 어셈블리를 어떻게 배포하는지에 대한 자세한 정보는 Developing a Silverlight Library Assembly를 보세요. 리소스 파일의 경우는 Application Services를 보세요.


애플리케이션 서비스

Application은 또한 일반적으로 애플리케이션에서 요구하는 몇 가지 애플리케이션 서비스를 제공합니다. 가장 중요한 서비스는 애플리케이션이 시작될 때 보여줄 사용자 인터페이스(UI)를 지정하는 기능입니다. 추가적인 서비스는 라이프타임 관리, 애플리케이션 스코프 리소스와 속성, 초기화 파라미터에 접근하기 및 처리되지 않은 예외 검출과 응답입니다.

Application 클래스에 의해 제공되는 서비스에 대한 자세한 정보는 Application Services를 보세요.


실버라이트 애플리케이션

지금까지 애플리케이션 클래스, 애플리케이션 어셈블리, 애플리케이션 패키지, 애플리케이션 서비스, 라이브러리 어셈블리 및 리소스 파일의 개요를 살펴봤습니다. 또한 실버라이트가 유연한 패키징과 배포를 위해 어떻게 in-package와 on-demand 파일을 지원하는지도 살펴봤습니다. 각 실버라이트 애플리케이션은 다음과 같은 방법으로 표현되는 하나 혹은 모든 것들의 조합입니다.

  • [필수] - 애플리케이션 어셈블리로 구현되고 애플리케이션 패키지에 포함된 애플리케이션 클래스와 서비스.
  • [선택] - 필수적인 애플리케이션 UI와 기능을 캡슐화하고 애플리케이션 패키지에 포함되는 in-package 라이브러리 어셈블리와 리소스 파일.
  • [선택] - 선택적인 UI와 기능을 캡슐화하고 애플리케이션 패키지와 나란히 포함되는 on-demand 라이브러리 어셈블리와 리소스 파일.

실버라이트 애플리케이션의 가능한 조합은 다음 그림에서 설명하고 있습니다.


관련 토픽

컨셉
Developing a Silverlight Application Assembly
Developing a Silverlight Library Assembly
Resource Files
Application Services
Deployment (Silverlight 2)

참조
Application 클래스

신고
Posted by gongdo

회사 그만두고 무려 두달간이나 무계획으로 놀아제꼈더니만 이젠 통장 잔고도 간당간당하고 해서 VB 간단한 알바거리를 하나 물어왔어요.

VS 2005, Orcas에서 C# 찝적대다가 오랫만에 VB6로 와보니 ...후우... 그동안 이 불편한걸 어떻게 쓰고 있었지... 란 생각이 드네요.
그래도 현업에서 쓸땐 VC6보단 훨씬 편하고 좋아했었는데 말이죠;

XP MCE의 미디어센터 프로그램의 일부 기능을 외부에서 제어하는 프로그램인데 MCE는 한번도 안써봤거든요. VB도 꽤나 오랫만에 손대고 회사 그만둘때 소스는 한줄도 안가지고 나온데다가 생판 처음보는 프로그램 제어. 으아... 처음부터 다시 시작하는 황량한 기분.

처음에 약간 당황했지만 역시나 구글링과 MSDN이면 안될게 없나봐요.
진득하니 한시간만 검색하니 필요한 자료 다 나오네요;
다시 한번 구글에 감사.

그리고 다른 개발 플랫폼은 안써봐서 잘 모르겠지만 MS 개발툴의 무서운 점은 MSDN에 있지 않나 싶어요. 찾는데 익숙해지면 처음 접하는 것도 금방 다룰 수 있게 해주는 것 같네요.
이번엔 MSDN에 감사.

오늘까지는 수고한 자신에게 상을 주고, 내일부터 다시 실버라잇으로 달립니다. :)

신고
Posted by gongdo
MSDN : http://msdn2.microsoft.com/en-us/library/ms748873.aspx

Imaging Overview

이 토픽은 Microsoft WPF 이미징 컴포넌트의 소개를 제공합니다. WPF 이미징은 개발자가 이미지를 화면에 표시하고 변형하고 포맷을 지정할 수 있게 합니다.

이 토픽은 다음 섹션을 담습니다.
WPF 이미징 컴포넌트

WPF 이미징은 Microsoft Windows내에서의 이미징 능력에 상당한 향상을 제공합니다. 비트맵을 보여주거나 커먼 컨트롤에 이미지를 사용하는 것 같은 이미징 능력은 이전엔 Microsoft Windows Graphics Device Interface(GDI)나 Microsoft Windows GDI+ 라이브러리에 의존했습니다. 이 API는 이미징 기능의 기반을 제공했지만 코덱 확장성이나 고선명 이미지 지원과 같은 기능이 부족했습니다. WPF 이미징은 GDI와 GDI+의 단점을 극복하기 위해 디자인 되었고, 애플리케이션에 이미지를 표시하고 사용하기 위한 새로운 API 세트를 제공합니다.

WPF 이미징 API에 접근 방법은 매니지드(managed) 컴포넌트와 언매니지드(unmanaged) 컴포넌트의 두 가지 방법이 있습니다. 언매니지드 컴포넌트는 다음 기능을 제공합니다.
  • 새롭거나 소유권 있는 이미지 포맷을 위한 확장성있는 모델
  • 비트맵(BMP), Joint Photographics Experts Group(JPEG), Portable Network Graphics(PNG), Tagged Image File Format(TIFF), Microsoft Windows Media Photo, Graphics Interchange Format(GIF) 및 icon(.ico)를 포함하는 네이티브 이미지 상에서의 향상된 성능과 보안
  • 채널당 32비트까지의 고 비트 이미지 데이터 보존
  • 손실 없는 이미지 배율 조절(scaling), 자르기(cropping) 및 회전
  • 단순화된 색상 관리
  • 파일 내에 있는 소유권 메타데이터 지원
매니지드 컴포넌트는 사용자 인터페이스(UI), 애니메이션 및 그래픽 같은 다른 WPF 기능과 이미지의 매끄러운(seamless) 통합을 제공하기 위해 언매니지드 인프라스트럭쳐를 이용합니다. 매니지드 컴포넌트는 또한 WPF 애플리케이션에서 자동화된 새 이미지 포맷의 인식을 가능케 하는 WPF 이미징 코덱 확장 모델의 혜택을 받습니다.

매니지드 WPF 이미징 API의 대부분은 System.Windows.Media.Imaging 네임스페이스에 존재하지만 ImageBrushImageDrawing과 같은 몇 가지 중요한 타입은 System.Windows.Media 네임스페이스에 존재하며 ImageSystem.Windows.Controls 네임스페이스에 존재합니다.

WPF 이미징 포맷

코덱은 특정한 미디어 포맷을 디코드하거나 인코드합니다. WPF 이미징은 BMP, JPEG, PNG, TIFF, Windows Media Photo, GIF 및 ICON 이미지 포맷을 위한 코덱을 포함합니다. 각 코덱은 애플리케이션이 디코드하고, ICON을 제외한 각각의 이미지 포맷을 인코드할 수 있게 합니다.

BitmapSource는 이미지의 디코딩과 인코딩에 사용되는 중요한 클래스입니다. 이것은 WPF 이미징 파이프라인의 기본 빌딩 블럭이며 어떤 크기와 해상도에서 픽셀의 단일한 불변의 세트를 나타냅니다. BitmapSource는 다중 프레임 이미지의 개별적인 프레임이 될 수 있고 또는 BitmapSource상의 변형 동작의 결과가 될 수도 있습니다. BitmapSourceBitmapFrame과 같은 WPF 이미징에서 사용되는 많은 주요 클래스의 부모가 됩니다.

BitmapFrame은 이미지 포맷의 실제 비트맵 데이터를 저장합니다. 많은 이미지 포맷이 단지 하나의 BitmapFrame만을 지원하지만 GIF나 TIFF와 같은 포맷은 한 이미지에서 다중 프레임을 지원합니다. 프레임은 디코더에게 입력 데이터로 사용되고 인코더에게 이미지 파일을 생성하도록 전달됩니다.

다음 예제는 BitmapSource로부터 BitmapFrame을 생성하고 TIFF 이미지에 추가하는 방법을 보여줍니다.

C#
BitmapSource image5 = BitmapSource.Create(

    width,

    height,

    96,

    96,

    PixelFormats.Indexed1,

    BitmapPalettes.WebPalette,

    pixels,

    stride);


FileStream stream5 = new FileStream("palette.tif", FileMode.Create);

TiffBitmapEncoder encoder5 = new TiffBitmapEncoder();

encoder5.Frames.Add(BitmapFrame.Create(image5));

encoder5.Save(stream5);


이미지 포맷 디코딩
이미지 디코딩은 시스템이 사용할 수 있도는 이미지 데이터로 이미지 포맷을 번역하는 것입니다. 번역된 이미지 데이터는 화면 표시, 처리 또는 다른 포맷으로 인코드될 수 있습니다. 디코더 섹션은 이미지 포맷에 기반합니다. 코덱 섹션은 디코더가 지정되지 않으면 자동으로 지정됩니다. Displaying Images in WPF의 예제 섹션은 자동 디코딩을 시연합니다. 사용자 정의 포맷 디코더는 언매니지드 WPF 이미징 인터페이스를 사용하여 개발되고 자동으로 디코더 섹션에 포함되어 시스템에 등록됩니다. 이것은 사용자 정의 포맷이 WPF 애플리케이션에서 자동으로 표시될 수 있도록 합니다.

다음 예제는 BMP 포맷 이미지를 디코드하기 위한 비트맵 디코더의 사용을 보여줍니다.(※역주: C++코드는 생략합니다.)

C#
// Open a Uri and decode a BMP image

Uri myUri = new Uri("tulipfarm.bmp", UriKind.RelativeOrAbsolute);

BmpBitmapDecoder decoder2 = new BmpBitmapDecoder(myUri, BitmapCreateOptions.PreservePixelFormat, BitmapCacheOption.Default);

BitmapSource bitmapSource2 = decoder2.Frames[0];


// Draw the Image

Image myImage2 = new Image();

myImage2.Source = bitmapSource2;

myImage2.Stretch = Stretch.None;

myImage2.Margin = new Thickness(20);


이미지 포맷 인코딩
이미지 인코딩은 이미지 데이터를 특정 이미지 포맷으로 번역하는 것입니다. 인코드된 이미지 데이터로는 새 이미지 파일을 생성할 수 있습니다. WPF 이미징은 위에서 기술한 이미지 포맷 각각을 위한 인코더를 제공합니다.

다음 예제는 새로 생성한 비트맵 이미지를 저장하는 인코더의 사용을 보여줍니다.

C#

FileStream stream = new FileStream("new.bmp", FileMode.Create);

BmpBitmapEncoder encoder = new BmpBitmapEncoder();

TextBlock myTextBlock = new TextBlock();

myTextBlock.Text = "Codec Author is: " + encoder.CodecInfo.Author.ToString();

encoder.Frames.Add(BitmapFrame.Create(image));

encoder.Save(stream);


WPF에서 이미지 표시하기

BitmapImage는 XAML 로딩을 위해 최적화된 특수한 BitmapSource이고 Image 컨트롤의 Source로 이미지를 표시하는 쉬운 방법입니다.

이미지 컨트롤 사용하기
Image는 프레임워크 엘리먼트이고 애플리케이션에서 이미지를 표시하는 주된 수단입니다. XAML에서 Image는 어트리뷰트 문법 또는 프로퍼티 문법의 두 가지 방법으로 사용될 수 있습니다. 다음 예제는 어트리뷰트 문법과 프로퍼티 태그 문법을 모두 사용하여 이미지를 200 픽셀 너비로 그리는 방법을 보여줍니다. 어트리뷰트 문법과 프로퍼티 문법의 더 자세한 정보는 Dependency Properties Overview를 참고하십시오.

XAML

<!-- 간단한 이미지 렌더링. 그러나 이 방법으로 렌더링하는 것은 애플리케이션 메모리의 사용량에는 좋지 않습니다. 같은 결과를 더 적은 메모리로 생성하는 아래쪽 마크업을 참고하십시오. -->

<Image Width="200"

Source="C:\Documents and Settings\All Users\Documents\My Pictures\Sample Pictures\Water Lilies.jpg"/>


<Image Width="200">

  <Image.Source>

    <!-- 상당한 애플리케이션 메모리를 아끼기 위해 이미지 소스의 BitmapImage의 DecodePixelWidth나 DecodePixelHeight값을 원하는 높이와 너비로 설정하십시오. 그렇게 하지 않으면 애플리케이션은 이미지를 화면에 표시될 크기가 아닌 그것의 보통 크기로 렌더링 될 것이라고 생각하고 캐슁할 것입니다. -->

    <!-- Note: 원래 비율을 보호하기 위해 DecodePixelHeight이나 DecodePixelWidth중 하나만을 설정하십시오. -->

    <BitmapImage DecodePixelWidth="200" 

    UriSource="C:\Documents and Settings\All Users\Documents\My Pictures\Sample Pictures\Water Lilies.jpg" />

  </Image.Source>

</Image>


다음 예제는 코드를 사용하여 이미지를 200픽셀 너비로 그리는 방법을 보여줍니다.

노트:
BitmapImage는 다중 속성에서 초기화 최적화를 위해 ISupportInitilize 인터페이스를 구현합니다. 속성 변경은 오직 객체 초기화 중에만 발생할 수 있습니다. 초기화가 시작되었음을 알리는 신호로 BeginInit을 호출하고 초기화가 완료되었음을 알리는 신호로 EndInit을 호출합니다. 일단 초기화되면 속성 변경은 무시됩니다.


C#
// 이미지 엘리먼트 생성

Image myImage = new Image();

myImage.Width = 200;


// 소스 생성

BitmapImage myBitmapImage = new BitmapImage();


// BitmapImage.UriSource는 반드시 BeginInit/EndInit 블럭 내에 있어야 합니다.

myBitmapImage.BeginInit();

myBitmapImage.UriSource = new Uri(@"C:\Documents and Settings\All Users\Documents\My Pictures\Sample Pictures\Water Lilies.jpg");


myBitmapImage.DecodePixelWidth = 200;

myBitmapImage.EndInit();

// 이미지 소스 설정

myImage.Source = myBitmapImage;


이미지 회전, 변환(converting) 및 자르기(cropping)
WPF는 BitmapImage의 속성을 사용하거나 CroppedBitmap이나 FormatConvertedBitmap과 같은 추가적인 BitmapSource 객체를 사용하여 이미지를 변형 할 수 있습니다. 이 이미지 변형은 이미지를 배율 조절하거나 회전할 수 있고 이미지의 픽셀 포맷을 바꾸거나 이미지를 자를 수 있습니다.

이미지 회전은 BitmapImageRotation 속성을 사용하여 작동됩니다. 회전은 90도씩만 증가될 수 있습니다. 다음 예제에서 이미지는 90도 회전됩니다.

XAML
<Image Width="150" Margin="5" Grid.Column="0" Grid.Row="1">
  <Image.Source>
    <TransformedBitmap Source="/sampleImages/watermelon.jpg" >
      <TransformedBitmap.Transform>
        <RotateTransform Angle="90"/>
      </TransformedBitmap.Transform>
    </TransformedBitmap>
  </Image.Source>
</Image>


C#
// 이미지 엘리먼트 생성
Image rotated90 = new Image();
rotated90.Width = 150;

// 이미지 소스로써 사용할 TransformedBitmap 생성
TransformedBitmap tb = new TransformedBitmap();

// 소스로써 사용할 (비트맵이미지)소스 생성
BitmapImage bi = new BitmapImage();
bi.BeginInit();
bi.UriSource = new Uri(@"sampleImages/watermelon.jpg", UriKind.RelativeOrAbsolute);
bi.EndInit();

// 속성은 반드시 BeginInit과 EndInit 호출 사이에서 설정해야 합니다.
tb.BeginInit();
tb.Source = bi;
// 이미지 회전을 설정
RotateTransform transform = new RotateTransform(90);
tb.Transform = transform;
tb.EndInit();
// 이미지 소스를 설정
rotated90.Source = tb;

이미지를 그레이스케일과 같은 다른 픽셀 포맷으로 변환하는 것은 FormatConvertedBitmap을 사용합니다. 다음 예제에서 이미지는 Gray4로 변환됩니다.

XAML
<!-- Grayscale XAML Image -->
<Image Width="200" Grid.Column="0" Grid.Row="1">
   <Image.Source>
      <FormatConvertedBitmap Source="/sampleImages/rocks.jpg"  DestinationFormat="Gray4" />
   </Image.Source>
</Image>


C#
// 이미지 엘리먼트 생성
Image grayImage = new Image();
grayImage.Width = 200;
grayImage.Margin = new Thickness(5);

// XAML에서 정의된 리소스를 사용하여 소스 생성
FormatConvertedBitmap fcb = new FormatConvertedBitmap(
   (BitmapImage)this.Resources["masterImage"],PixelFormats.Gray4,null,0);
// 이미지 소스 설정
grayImage.Source = fcb;

이미지를 자르기 위해서 ImageClip 속성이나 CroppedBitmap을 사용할 수 있습니다. 일반적으로 단지 이미지의 일부분만 보여주고 싶다면 Clip이 사용됩니다. 만약 잘린 이미지를 인코드하고 저장할 필요가 있다면 CroppedBitmap이 사용됩니다. 다음 예제에서 이미지는 EllipseGeometry를 사용한 Clip 속성을 사용하여 잘립니다.

XAML
<!-- Cropping an Image using Clip -->
<Image Width="200" Grid.Column="0" Grid.Row="5" Margin="5"
   Source="/sampleImages/gecko.jpg">
  <Image.Clip>
    <EllipseGeometry Center="75,50" RadiusX="50" RadiusY="25" />
  </Image.Clip>
</Image>


C#
// 클리핑을 위한 이미지 생성
Image clipImage = new Image();
clipImage.Width = 200;
clipImage.Margin = new Thickness(5);
 
// 소스 생성 및 설정
BitmapImage bi = new BitmapImage();
// BitmapImage.UriSource는 반드시 BeginInit/EndInit 블럭 내에 있어야 합니다.
bi.BeginInit();
bi.UriSource = new Uri("pack://application:,,/sampleImages/gecko.jpg");
bi.EndInit();
clipImage.Source = bi;

// EllipseGeometry를 사용하여 클립
EllipseGeometry clipGeometry = new EllipseGeometry(new Point(75, 50), 50, 25);
clipImage.Clip = clipGeometry;

이미지 늘리기
Stretch 속성은 이미지가 컨테이너에 어떻게 늘려져서 채워질지를 제어합니다. Stretch 속성은 Stretch 열거값에서 정의된 다음 값을 받아들입니다.
  • None: 이미지는 출력 영역을 늘려져서 채우지 않습니다. 이미지가 출력 영역보다 클 경우 이미지는 출력 영역에 그려지고 맞지 않는 부분은 잘립니다.
  • Fill: 이미지는 출력 영역에 맞춰 배율이 조절됩니다. 이미지의 높이와 너비가 독립적으로 조절되기 때문에 이미지의 원래 비율은 보호되지 않을 것입니다. 이미지는 출력 컨테이너를 완전히 채우도록 정렬되어 비뚤어질 것입니다.
  • Uniform: 이미지는 출력 영역 내에 완전하게 맞춰서 배율 조절 됩니다. 이미지의 비율은 보호됩니다.
  • UnformFill: 이미지는 출력 영역을 이미지의 원래 배율을 보존하면서 완전하게 채워 배율 조절 됩니다.
※역주: 원문에는 여기에 각각의 Stretch를 다르게 설정한 예제 코드만 나와있습니다. 여기에서는 이 코드를 거의 그대로 사용한 수정된 코드 및 결과물을 대신 올립니다.

XAML
<Window x:Class="WindowsApplication1.Window1" xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"

    xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"

    Title="WindowsApplication1" Height="500" Width="400">

  <DockPanel>


    <Border DockPanel.Dock="Top" Background="Black">

      <TextBlock Foreground="White" HorizontalAlignment="Stretch" FontSize="20">

        Stretching an Image

      </TextBlock>

    </Border>


    <Grid Name="simpleGrid"

      Margin="10"

      ShowGridLines="True"

      VerticalAlignment="Center"

      HorizontalAlignment="Center">

      <Grid.ColumnDefinitions>

        <ColumnDefinition Width="175" />

        <ColumnDefinition Width="175" />

      </Grid.ColumnDefinitions>

      <Grid.RowDefinitions>

        <RowDefinition Height="200"/>

        <RowDefinition Height="200"/>

      </Grid.RowDefinitions>

      <!-- Labels -->

      <TextBlock

        Grid.Column="0" Grid.Row="0">None</TextBlock>

      <TextBlock

        Grid.Column="1" Grid.Row="0">Uniform</TextBlock>

      <TextBlock

        Grid.Column="0" Grid.Row="1">UniformToFill</TextBlock>

      <TextBlock

        Grid.Column="1" Grid.Row="1">Fill</TextBlock>

      <Border Grid.Column="0" Grid.Row="0" BorderThickness="1" BorderBrush="Black">

        <!-- None: 이미지는 배율 조절되지 않습니다. 이미지가 출력 영역보다 크다면 이미지는 출력 영역의 크기로 잘릴 것입니다.-->

        <Image

          Source="sampleImages/만년삼.gif"

          Stretch="None" />

      </Border>

      <Border Grid.Column="1" Grid.Row="0" BorderThickness="1" BorderBrush="Black">

        <!-- Uniform: 출력 영역에 맞춰 배율 조절합니다. 비율은 보호됩니다.-->

        <Image

          Source="sampleImages/만년삼.gif"

          Stretch="Uniform" />

      </Border>

      <Border Grid.Column="0" Grid.Row="1" BorderThickness="1" BorderBrush="Black">

        <!-- UniformToFill: 출력 영역을 완전히 채우도록 배율 조절됩니다. 비율은 보호됩니다. 크기에 따라 잘릴 수 있습니다.-->

        <Image 

          Source="sampleImages/만년삼.gif"

        Stretch="UniformToFill" />

      </Border>

      <Border Grid.Column="1" Grid.Row="1" BorderThickness="1" BorderBrush="Black">

        <!-- Fill: 출력 영역을 완전히 채우도록 배율 조절됩니다. 비율은 보호되지 않을 것입니다.-->

        <Image

          Source="sampleImages/만년삼.gif"

          Stretch="Fill" />

      </Border>

    </Grid>

  </DockPanel>


</Window>




이미지로 페인팅하기
이미지는 또한 Brush로 페인팅하여 애플리케이션에서 표시될 수 있습니다. 브러쉬는 단순한 단일 컬러에서 복잡한 패턴의 세트와 이미지까지 어떤 것으로도 UI 객체를 칠할 수 있게 합니다. 이미지를 칠하려면 ImageBrush를 사용합니다. ImageBrush는 자신의 내용을 비트맵 이미지로 정의하는 TileBrush의 타입입니다. ImageBrushImageSource 속성에서 지정된 단일 이미지를 표시합니다. 이미지가 늘려지고 정렬되고 배열되는 방법을 제어할 수 있고 왜곡을 막고 패턴과 다른 효과를 제작하는 것을 가능케 합니다. 다음 그림은 ImageBrush로 얻을 수 있는 몇 가지 효과를 보여줍니다.

도형, 컨트롤, 텍스트 및 기타를 채울 수 있는 이미지 브러쉬


다음 예제는 버튼의 배경을 ImageBrush를 사용하여 이미지로 칠할 수 있는 방법을 보여줍니다.

XAML
<!-- 버튼의 배경 속성을 이미지 브러쉬로 설정합니다. 결과적으로 버튼은 배경에 이미지를 가지게 됩니다. -->

<Button Grid.Row="3" Grid.Column="2"

 Height="75" Width="100" Foreground="White" FontWeight="Bold"

 HorizontalAlignment="Left">

  A Button

  <Button.Background>

    <ImageBrush ImageSource="sampleImages\blueberries.jpg" />

  </Button.Background>

</Button>


ImageBrush와 칠하기에 대한 추가적인 정보는 Painting with Images, Drawings, and Visuals를 참고하십시오.

이미지 메타데이터

어떤 이미지 파일은 컨텐트나 파일의 특성을 기술하는 메타데이터를 포함합니다. 예를 들어 대부분의 디지털 카메라는 이미지 캡쳐에 사용된 카메라의 메이커와 모델에 관한 메타데이터를 포함하는 이미지를 생성합니다. 각 이미지 포맷은 메타데이터를 다르게 처리하지만 WPF 이미징은 지원되는 각 이미지 포맷을 위한 통합된 메타데이터 저장과 얻는 수단을 제공합니다.

메타데이터 접근은 BitmapSource 객체의 Metadata 속성을 통해 제공됩니다. Metadata는 이미지가 담고 있는 모든 메타데이터를 포함하는 BitmapMetadata 객체를 반환합니다. 이 데이터는 하나의 메타데이터 스키마 또는 다른 스키마의 조합일 수 있습니다. WPF 이미징은 다음의 메타데이터 스키마를 지원합니다. Exchangeable image file(Exif), tExt(PNG Textual Data), Image File Directory(IFD), International Press Telecommunications Council(IPTC) 및 Extensible Metadata Platform(XMP)

메타데이터 읽기 프로세스를 단순화하기 위해 BitmapMetadataAuthor, TitleCameraModel과 같이 쉽게 접근할 수 있는 몇 가지 명명된 속성을 제공합니다. 이들 명명된 속성의 대부분은 또한 메타데이터 기록에도 사용될 수 있습니다. 메타데이터 읽기를 위한 추가적인 지원은 메타데이터 쿼리 리더가 제공합니다. GetQuery 메소드는 "/app1/exif/"와 같은 문자열 쿼리를 제공함으로써 메타데이터 쿼리 리더를 받습니다. 다음 예제에서 GetQuery는 "/Text/Description" 위치에 저장된 텍스트를 얻기 위해 사용됩니다.

C#
// 텍스트 블럭에 비트맵 이미지의 메타데이터를 추가
TextBlock myTextBlock = new TextBlock();
myTextBlock.Text = "The Description metadata of this image is: " + pngInplace.GetQuery("/Text/Description").ToString();

메타데이터를 쓰기 위해 메타데이터 쿼리 라이터(writer)가 사용됩니다. SetQuery는 쿼리 라이터를 얻고 원하는 값을 설정합니다. 다음 예제에서 SetQuery는 "/Text/Description" 위치에 저장된 텍스트를 쓰기 위해 사용됩니다.

C#
Stream pngStream = new System.IO.FileStream("smiley.png", FileMode.Open, FileAccess.ReadWrite, FileShare.ReadWrite);

PngBitmapDecoder pngDecoder = new PngBitmapDecoder(pngStream, BitmapCreateOptions.PreservePixelFormat, BitmapCacheOption.Default);

BitmapFrame pngFrame = pngDecoder.Frames[0];

InPlaceBitmapMetadataWriter pngInplace = pngFrame.CreateInPlaceBitmapMetadataWriter();

if (pngInplace.TrySave() == true)

{ pngInplace.SetQuery("/Text/Description", "Have a nice day."); }

pngStream.Close();



코덱 확장성

WPF 이미징의 핵심 기능은 새로운 이미지 코덱을 위한 확장성 있는 모델입니다. 이 언매니지드 인터페이스는 코덱 개발자가 WPF와 코덱을 통합할 수 있게 하므로 새로운 이미지 포맷이 WPF 애플리케이션에서 자동으로 사용될 수 있습니다.

확장 API의 샘플은 Win32 Sample Codec을 참고하십시오. 이 샘플은 사용자 정의 이미지 포맷을 위한 디코더와 인코더를 만드는 방법을 제시합니다.

노트:
코덱은 그것을 인식하기 위해 반드시 시스템을 위한 디지털 사인이 되어 있어야 합니다.

See also

Reference
BitmapSource
BitmapImage
Image
BitmapMetadata

Other Resources
Win32 Sample Codec
Photo Store Demo
신고
Posted by gongdo
MSDN : http://msdn2.microsoft.com/en-us/library/ms748373.aspx

WPF Graphics Rendering Overview

이 토픽은 WPF 비주얼 레이어의 개요를 제공하며 WPF 모델에서 렌더링 지원을 위한 Visual 클래스의 역할에 초점을 맞추고 있습니다.

이 토픽은 다음 섹션을 담고 있습니다.
Visual 객체의 역할

Visual 클래스는 모든 FrameworkElement 객체가 파생(derive)하는 기본 추상 클래스입니다. 또한 WPF에서 새 컨트롤을 작성하는 엔트리 포인트와 Win32 애플리케이션 모델에서의 윈도 핸들(HWND)처럼 생각할 수 있는 많은 방법을 제공합니다.

Visual 객체는 핵심 WPF 객체로써 주 역할은 렌더링 지원을 제공하는 것입니다. Button이나 TextBox와 같은 사용자 인터페이스 컨트롤은 Visual 클래스에서 파생되며, 렌더링 데이터를 지속하기 위해 사용합니다. Visual 객체는 다음 지원을 제공합니다.
  • 화면 출력 : 비주얼의 그릴 내용을 지속적으로, 직렬화하여 렌더링.
  • 변형(Transformations) : 비주얼 상의 변형을 실행.
  • 클리핑(Clipping) : 비주얼을 위한 클리핑 영역(region) 지원을 제공.
  • 충돌 검사(Hit testing) : 좌표나 지오메트리가 비주얼의 영역 내에 포함되는지를 결정.
  • 경계 박스(Bounding box) 계산 : 비주얼의 경계 사각형(Bounding rectangle)을 결정.
※역주: Bounding rectangle은 어떤 비정형의 비주얼 객체를 완전히 포함하는 최소의 크기를 가진 사각형을 말합니다. 다음 그림을 참고하십시오.


그러나 Visual 객체는 다음과 같은 비렌더링 기능을 위한 지원은 포함하지 않습니다.
  • 이벤트 핸들링
  • 레이아웃
  • 스타일
  • 데이터 바인딩
  • 세계화(Globalization)
Visual은 파생되어야 하는 자식 클래스로부터 public abstract 클래스로써 노출됩니다. 다음 그림은 WPF에서 노출되는 비주얼 객체의 계층 구조를 보여줍니다.

Visual 클래스 계층 구조
사용자 삽입 이미지

DrawingVisual 클래스
DrawingVisual은 도형, 이미지나 텍스트를 그리는 가벼운 드로잉 클래스입니다. 이 클래스는 레이아웃이나 이벤트 핸들링을 제공하지 않기 때문에 그것의 런타임 성능을 향상시키는 가벼움이 고려되었습니다. 이런 이유로 드로잉은 배경과 클립아트에 이상적입니다. DrawingVisual은 사용자 정의 비주얼 객체를 생성하는데 사용될 수도 있습니다. 더 자세한 정보는 Using DrawingVisual Objects를 참고하십시오.

Viewport3DVisual 클래스
Viewport3DVisual2D VisualVisual3D 객체간의 다리를 제공합니다. Visual3D 클래스는 모든 3D 비주얼 엘리먼트를 위한 기반 클래스입니다. Viewport3DVisualCamera 값과 Viewport 값의 정의를 요구합니다. 카메라(camera)는 씬(scene)을 볼(view) 수 있게 합니다. 뷰포트(viewport)는 2D 표면상에 프로젝션 맵을 생성합니다. WPF에서의 3D에 관한 더 자세한 정보는 3-D Graphics Overview를 참고하십시오.

ContainerVisual 클래스
ContainerVisual 클래스는 Visual 객체의 컬렉션을 위한 컨테이너로써 사용됩니다. DrawingVisual 클래스는 비주얼 객체의 컬렉션을 담을 수 있게 하는 ContainerVisual 클래스에서 파생됩니다.

Visual 객체에서 드로잉 컨텐트
Visual
객체는 자신의 렌더 데이터를 벡터 그래픽 인스트럭션 목록(vector graphics instruction list)으로 저장합니다. 인스트럭션(※역주:단위 명령어) 목록의 각 아이템은 그래픽 데이터와 연관된 리소스의 로우레벨 세트를 직렬화된 포맷으로 나타냅니다. 드로잉 컨텐트를 담을 수 있는 렌더 데이터는 네 가지 종류가 있습니다.

드로잉 컨텐트 종류
설명
벡터 그래픽
벡터 그래픽 데이터 및 모든 연관된 BrushPen 정보를 나타냅니다.
이미지
Rect에 의해 정의된 영역(region) 내의 이미지를 나타냅니다.
도안(Glyph)
특정 폰트 리소스의 도안 순서인 GlyphRun을 그리는 드로잉을 나타냅니다. 텍스트는 이렇게 해서 표시됩니다.
비디오
비디오를 그리는 드로잉을 나타냅니다.


DrawingContextVisual이 비주얼 컨텐트와 함께 위치할 수 있도록 합니다. DrawingContext 객체의 draw 커맨드를 사용하면 실제로는 그래픽 시스템에 의해 나중에 사용될 렌더 데이터의 세트를 저장하게되며 실시간으로 스크린에 드로잉하는 것이 아닙니다.

Button과 같은 WPF 컨트롤을 만든다면 컨트롤은 명시적으로 스스로를 드로잉할 렌더 데이터를 생성합니다. 예를 들어, ButtonContent 속성을 설정함으로써 컨트롤이 도안의 렌더링 표현을 저장하게 합니다.

VisualDrawingGroup내에 담긴 하나 이상의 Drawing 객체로 그것의 컨텐트를 설명합니다. DrawingGroup은 또한 불투명도 마스크, 변형, 비트맵 효과 및 컨텐트에 적용될 다른 오퍼레이션을 설명합니다. DrawingGroup 명령은 컨텐트가 그려질 때 다음 순서로 적용됩니다. OpacityMask, Opacity, BitmapEffect, ClipGeometry, GuidelineSet 그리고 Transform.

다음 그림은 렌더링 시퀀스동안 적용되는 DrawingGroup 오퍼레이션의 순서를 보여줍니다.

DrawingGroup 오퍼레이션의 순서
사용자 삽입 이미지
더 자세한 정보는 Drawing Objects Overview를 참고하십시오.

Visual 레이어에서의 드로잉 컨텐트
DrawingContext
를 직접 인스턴스화 할 수 없으며, System.Windows.Media.DrawingGroup.Open이나 System.Windows.Media.DrawingVisual.RenderOpen과 같은 메소드를 통해 드로잉 컨텍스트를 획득할 수 있습니다. 다음 예제는 DrawingVisual에서 DrawingContext를 얻고 사각형을 그리는데 사용합니다.

C#
// 사각형을 포함한 DrawingVisual을 생성.
private DrawingVisual CreateDrawingVisualRectangle()
{
    DrawingVisual drawingVisual = new DrawingVisual();

    // 새 드로잉을 생성하기 위해 DrawingContext얻음.
    DrawingContext drawingContext = drawingVisual.RenderOpen();

    // 사각형을 생성하고 DrawingContext로 그것을 칠함.
    Rect rect = new Rect(new Point(160, 100), new Size(320, 80));
    drawingContext.DrawRectangle(Brushes.LightBlue, (Pen)null, rect);

    // 드로잉 컨텐트를 지속.
    drawingContext.Close();

    return drawingVisual;
}

비주얼 레이어에 있는 드로잉 컨텐트 열거
추가적인 다른 사용법으로, Drawing 객체는 또한 Visual의 켄텐츠를 열거하기 위한 객체 모델을 제공합니다.

노트:
비주얼의 컨텐츠를 열거하면 Drawing 객체를 얻을 수 있지만 근본적으로 벡터 그래픽 인스트럭션 리스트로써 렌더 데이터의 표현을 얻을 수 없습니다.

다음 예제는 GetDrawing 메소드를 사용하여 VisualDrawingGroup 값을 얻고 열거합니다.

C#
public void RetrieveDrawing(Visual v)
{
    DrawingGroup dGroup = VisualTreeHelper.GetDrawing(v);
    EnumDrawingGroup(dGroup);

}

// DrawingGroup내의 드로잉을 열거.
public void EnumDrawingGroup(DrawingGroup drawingGroup)
{
     DrawingCollection dc = drawingGroup.Children;

     // 드로잉 컬렉션에 있는 드로잉을 열거.
     foreach (Drawing drawing in dc)
     {
         // 드로잉이 DrawingGroup이면, 재귀 호출.
         if (drawing.GetType() == typeof(DrawingGroup))
         {
             EnumDrawingGroup((DrawingGroup)drawing);
         }
         else if (drawing.GetType() == typeof(GeometryDrawing))
         {
             // 드로잉 종류에 따른 동작 실행.
         }
         else if (drawing.GetType() == typeof(ImageDrawing))
         {
             // 드로잉 종류에 따른 동작 실행.
         }
         else if (drawing.GetType() == typeof(GlyphRunDrawing))
         {
             // 드로잉 종류에 따른 동작 실행.
         }
         else if (drawing.GetType() == typeof(VideoDrawing))
         {
             // 드로잉 종류에 따른 동작 실행.
         }
     }
}

비주얼 객체가 컨트롤을 빌드하는 방법

많은 WPF의 객체는 다른 비주얼 객체들로 구성되어 있으며 변화하는 자손 객체의 계층구조를 담을 수 있다는 걸 의미합니다. WPF의 컨트롤과 같은 많은 사용자 인터페이스 엘리먼트는 렌더링 엘리먼트의 다른 종류를 나타내는 다중 비주얼 객체로 구성되어 있습니다. 예를 들어 Button 컨트롤은 ClassicBorderDecorator, ContentPresenterTextBlock을 포함한 여러개의 다른 객체를 담을 수 있습니다.

다음 코드는 마크업에서 정의된 Button 컨트롤을 보여줍니다.

XAML
<Button Click="OnClick">OK</Button>


기본적인 Button 컨트롤을 구성하는 비주얼 객체를 열거한다면 아래와 같은 비주얼 객체의 계층 구조를 확인할 수 있을 것입니다.

비주얼 트리 계층 구조의 다이어그램

Button 컨트롤은 ContentPresenter 엘리먼트를 포함하는 ClassicBorderDecorator 엘리먼트를 포함합니다. ClassicBorderDecorator 엘리먼트는 Button을 위한 테두리와 배경을 그릴 책임이 있습니다. ContentPresenter 엘리먼트는 Button의 내용을 표시할 책임이 있습니다. 이 경우에서 텍스트를 표시하기 때문에 ContentPresenter 엘리먼트는 TextBlock 엘리먼트를 포함합니다. Button 컨트롤이 ContentPresenter를 사용한다는 사실은 컨텐트가 ImageEllipseGeometry와 같은 다른 엘리먼트로 대체될 수 있다는 것을 의미합니다.

컨트롤 템플릿
컨트롤의 계층으로 컨트롤을 확장하는 핵심은 ControlTemplate입니다. 컨트롤 템플릿은 컨트롤의 기본 비주얼 계층을 말합니다. 명시적으로 컨트롤을 참조하면 암시적으로 그것의 비주얼 계층을 참조합니다. 컨트롤을 사용자 정의된 비주얼 형태로 만들기 위해 컨트롤 템플릿의 기본 값을 오버라이드 할 수 있습니다. 예를 들어 Button 컨트롤의 배경 색상 값을 단일 색상 값 대신 선형 그레이디언트 색상 값으로 변경할 수 있습니다. 더 자세한 정보는 Button ControlTemplate Example을 참고하십시오.

Button 컨트롤과 같은 사용자 인터페이스 엘리먼트는 컨트롤의 전체 렌더링 정의를 설명하는 몇 개의 벡터 그래픽 인스트럭션 리스트를 포함합니다. 다음 코드는 마크업에서 정의된 Button 컨트롤을 보여줍니다.

XAML
<Button Click="OnClick">
  <Image Source="images\greenlight.jpg"></Image>
</Button>

Button 컨트롤을 구성하는 비주얼 객체와 벡터 그래픽 인스트럭션 리스트를 열거한다면 아래 그림과 같은 객체의 계층 구조를 확인할 수 있을 것입니다.

비주얼 트리와 렌더링 데이터의 다이어그램

Button 컨트롤은 ContentPresenter 엘리먼트를 포함하는 ClassicBorderDecorator 엘리먼트를 포함합니다. ClassicBorderDecorator 엘리먼트는 버튼의 경계나 배경을 만드는 모든 구분된 그래픽 엘리먼트를 그릴 책임을 가지고 있습니다. ContentPresenter 엘리먼트는 Button의 내용을 표시할 책임이 있습니다. 이 경우에서 이미지를 표시하기 때문에 ContentPresenter 엘리먼트는 Image 엘리먼트를 포함하게 됩니다.

비주얼 객체와 벡터 그래픽 인스트럭션 목록에 관하여 주의해야 할 몇 가지 사항이 있습니다.
  • 계층 구조에서 순서는 드로잉 정보의 렌더링 순서를 말합니다. 루트 비주얼 엘리먼트에서 자식 엘리먼트까지 왼쪽에서 오른쪽, 위에서 아래로 순회(traversed)됩니다. 엘리먼트가 비주얼 차일드 엘리먼트를 가진다면 엘리먼트의 형제보다 먼저 순회됩니다.
  • 계층 구조에서 ContentPresenter와 같은 리프가 아닌 노드 엘리먼트는 자식 엘리먼트를 담게 되며 인스트럭션 목록을 포함하지 않습니다.
  • 비주얼 엘리먼트가 벡터 그래픽 인스트럭션 리스트와 비주얼 자식 모두를 포함한다면 부모 비주얼 엘리먼트에 있는 인스트럭션 목록은 어떤 자식 비주얼 객체에 있는 드로잉보다 먼저 그려집니다.
  • 벡터 그래픽 인스트럭션 목록에 있는 아이템은 왼쪽에서 오른쪽으로 그려집니다.
비주얼 트리

비주얼 트리는 애플리케이션의 사용자 인터페이스에 사용되는 모든 비주얼 엘리먼트를 포함합니다. 비주얼 엘리먼트가 지속되는 드로잉 정보를 담기 때문에 비주얼 트리를 디스플레이 장치에 출력물을 구성하기 위해 필요한 모든 렌더링 정보를 담는 씬 그래프로 생각할 수 있습니다. 이 트리는 코드든 마크업이든 애플리케이션에 의해 직접적으로 생성된 모든 비주얼 엘리먼트의 집합입니다. 비주얼 트리는 또한 컨트롤과 데이터 객체와 같은 엘리먼트의 템플릿 확장에 의해 생성된 모든 비주얼 엘리먼트도 포함합니다.

다음 코드는 마크업에서 정의된 StackPanel 엘리먼트를 보여줍니다.

XAML
<StackPanel>
  <Label>User name:</Label>
  <TextBox />
  <Button Click="OnClick">OK</Button>
</StackPanel>

마크업 예제의 StackPanel 엘리먼트를 구성하는 비주얼 객체를 열거한다면 아래 그림과 같은 비주얼 객체의 계층 구조를 확인할 수 있을 것입니다.

비주얼 트리 계층 구조의 다이어그램


렌더링 순서
비주얼 트리는 WPF 비주얼과 드로잉 객체의 렌더링 순서를 결정합니다. 순회의 순서는 비주얼 트리의 최상위 노드인 루트 비주얼에서 시작됩니다. 루트 비주얼의 자식은 왼쪽에서 오른쪽으로 순회됩니다. 비주얼이 자식을 가진다면 그 자식은 비주얼의 형제보다 먼저 순회됩니다. 이것은 자식 비주얼의 컨텐트는 비주얼 자신의 컨텐트에 앞서 그려진다는 것을 의미합니다.

비주얼 트리 렌더링 순서의 다이어그램


루트 비주얼
root visual
은 비주얼 트리 계층 구조에서 최상위 엘리먼트입니다. 대부분의 애플리케이션에서 루트 비주얼의 기반 클래스는 Window 또는 NavigateWindow입니다. 그러나 Win32 애플리케이션에서 비주얼 객체를 호스팅한다면 루트 비주얼은 Win32 윈도에서 호스팅한 최상위 비주얼이 될 것입니다. 더 자세한 정보는 Tutorial: Hosting Visual Objects in a Win32 Application을 참고하십시오.

로지컬 트리와의 관계
WPF에서 로지컬 트리는 런타임시 애플리케이션의 엘리먼트를 말합니다. 비록 이 트리를 직접 다루지 않더라도 이 애플리케이션의 뷰는 속성 상속과 이벤트 라우팅을 이해하는데 유용합니다. 비주얼 트리와는 다르게 로지컬 트리는 ListItem과 같은 비-비주얼 데이터 객체를 나타낼 수 있습니다. 많은 경우에서 로지컬 트리는 애플리케이션의 마크업 정의와 매우 밀접하게 연결됩니다. 다음 코드는 마크업에서 정의된 DockPanel 엘리먼트를 보여줍니다.

XAML
<DockPanel>
  <ListBox>
    <ListBoxItem>Dog</ListBoxItem>
    <ListBoxItem>Cat</ListBoxItem>
    <ListBoxItem>Fish</ListBoxItem>
  </ListBox>
  <Button Click="OnClick">OK</Button>
</DockPanel>


마크업 예제의 DockPanel 엘리먼트를 구성하는 로지컬 객체를 열거한다면 아래 그림과 같은 로지컬 객체의 계층 구조를 확인할 수 있을 것입니다.

로지컬 트리의 다이어그램

비주얼 트리와 로지컬 트리 모두 애플리케이션의 현재 세트, 모든 엘리먼트의 추가, 삭제 또는 변경의 반영에 동기화됩니다. 그러나 이 트리들은 애플리케이션의 뷰를 다르게 나타냅니다. 비주얼 트리와 달리 로지컬 트리는 컨트롤의 ContentPresenter 엘리먼트를 확장하지 않습니다. 이것은 같은 객체의 세트를 위한 로지컬 트리와 비주얼 트리간의 일대일 일치성이 없다는 것을 의미합니다. 사실 LogicalTreeHelper 객체의 GetChildren 메소드와 VisualTreeHelper 객체의 GetChild 메소드를 파라미터로 같은 엘리먼트를 사용하여 호출하는 것은 다른 결과를 산출합니다.

로지컬 트리에 관한 더 자세한 정보는 Element Tree를 참고하십시오.

XamlPad로 비주얼 트리를 보기
WPF 툴인 XamlPad는 현재 정의된 XAML 컨텐트와 일치하는 비주얼 트리를 보여주고 탐색하기 위한 옵션을 제공합니다. 비주얼 트리를 표시하기 위해 메뉴 바에 있는 Show Visual Tree 버튼을 클릭하십시오. 다음 그림은 XamlPad의 Visual Tree Explorer패널에서 비주얼 트리 노드에 있는 XAML 컨텐트를 확장한 것입니다.

XamlPad에서 Visual Tree Explorer

Label, TextBoxButton 컨트롤이 XamlPad의 Visual Tree Explorer에서 각각 분리된 비주얼 객체 계층 구조를 표시하는 것에 주목하십시오. 이것은 WPF 컨트롤이 그 컨트롤의 비주얼 트리를 담는 ControlTemplate를 가지고 있기 때문입니다. 명시적으로 컨트롤을 참조하면 그것의 비주얼 계층 구조를 암시적으로 참조하게 됩니다.

비주얼 성능 분석
WPF는 애플리케이션의 런타임 동작 분석과 적용 가능한 성능 최적화의 종류의 결정을 가능케 하는 성능 분석 툴 스위트(suite)를 제공합니다. Visual Profiler 툴은 애플리케이션의 비주얼 트리에 직접 매핑된 성능 데이터의 풍부한 시각적인 뷰를 제공합니다. 이 스크린 샷에서 Visual Profiler의 CPU Usage 섹션은 렌더링이나 레이아웃 같은 오브젝트의 WPF 서비스 사용에 대한 정확한 구분을 제공합니다.

Visual Profiler 화면 출력
사용자 삽입 이미지
WPF 성능 툴에 관한 더 자세한 정보는 Performance Profiling Tools for WPF를 참고하십시오.

비주얼 렌더링 동작

WPF는 비주얼 객체- 보유 모드 그래픽, 벡터 그래픽 및 장치 독립적인 그래픽 - 의 렌더링 동작에 영향을 주는 몇 가지 기능을 소개합니다.

보유 모드 그래픽(Retained Mode Graphics)
비주얼 객체의 역할을 이해하는 핵심 중 하나는 즉시 모드(immediate mode)보유 모드(retained mode) 그래픽 시스템간의 차이를 이해하는 것입니다. 표준 Win32 애플리케이션은 GDI나 GDI+을 사용한 즉시 모드 그래픽 시스템에 기반합니다. 이것은 애플리케이션이 윈도의 크기가 변경되거나 객체가 자신의 시각적인 형태를 변경하는 것 같은 액션이 있을 때 무효화된 클라이언트 영역의 부분을 다시 칠할(repainting) 책임이 있다는 것을 의미합니다.

Win32 렌더링 시퀀스의 다이어그램


이에 비해 WPF는 보유 모드 시스템을 사용합니다. 이것은 시각적인 형태를 가지는 애플리케이션 객체가 직렬화된 드로잉 데이터의 세트를 정의한다는 것을 의미합니다. 일단 드로잉 데이터가 정의되면 시스템은 그 이후의 애플리케이션 객체를 그리기 위한 모든 다시 칠하기 요청에 대해 응답할 책임을 가집니다. 보유 모드 그래픽 시스템의 장점은 그릴 정보가 항상 애플리케이션에 의해 직렬화된 상태를 유지하지만 렌더링할 책임은 시스템에게 넘어간다는 점입니다.

WPF 렌더링 시퀀스의 다이어그램


지능적인 리드로잉
보유 모드 그래픽을 사용하여 얻을 수 있는 가장 큰 이득 중 하나는 WPF가 애플리케이션에서 리드로잉될 필요가 있을 때 효과적으로 최적화 할 수 있다는 것입니다. 심지어 다양한 불투명도의 레벨을 가진 복잡한 신에서도 일반적으로 최적화된 리드로잉를 위한 특별한 동작을 작성할 필요가 없습니다. 이것을 Win32 프로그래밍에서 업데이트 영역 내의 다시 그릴 양을 최소화하여 애플리케이션을 최적화하기 위해 들일 수 있는 엄청난 노력의 낭비와 비교해 보십시오. Win32 애플리케이션에서 다시 그리기 최적화와 관계된 복잡한 유형의 예를 Redrawing in the Update Region에서 참고하십시오.

벡터 그래픽
WPF는 렌더링 데이터 포맷으로써 벡터 그래픽을 사용합니다. 벡터 그래픽스 - Scalable Vector Graphics(SVG), Windows metafiles(.wmf) 및 트루타입 폰트를 포함하는 - 는 렌더링 데이터를 저장하고 원본 그래픽을 사용하여 이미지를 재생성하는 방법을 기술하는 인스트럭션의 목록으로 그것을 전달합니다. 예를 들어 트루타입 폰트는 픽셀을 배열이 아닌 직선, 곡선 및 커맨드의 세트를 기술하는 아웃라인 폰트입니다. 벡터 그래픽의 주요한 장점 중 하나는 크기와 해상도에 관계 없이 스케일(배율 조절) 할 수 있는 능력입니다.

벡터 그래픽과 달리 비트맵 그래픽은 이미지를 나타내는 데 픽셀 단위로 렌더링 데이터를 저장하고, 특정 해상도에 맞춰 미리 렌더링됩니다. 비트맵과 벡터 그래픽 포맷간의 주요한 차이점 중 하나는 원본 이미지에 대한 충실도입니다. 예를 들어 원본 이미지의 크기가 변경되면 비트맵 그래픽 시스템은 이미지를 잡아 늘이는(stretch) 반면 벡터 그래픽 시스템은 이미지의 충실도를 보존하면서 스케일링 합니다.

다음 그림은 300% 리사이즈된 원본 이미지를 보여줍니다. 벡터 그래픽 이미지와는 달리 비트맵 그래픽 이미지의 잡아 늘여져서 왜곡된 모습을 주목하십시오.

래스터와 벡터 그래픽간의 차이점

다음 마크업은 두 Path 엘리먼트의 정의를 보여줍니다. 두번째 엘리먼트는 첫번째 엘리먼트의 드로잉 인스트럭션을 300% 확대하는 데 ScaleTransform을 사용합니다. Path 엘리먼트의 드로잉 인스트럭션이 변형되지 않고 남아있는 것에 주목하십시오.

XAML
<Path
  Data="M10,100 C 60,0 100,200 150,100 z"
  Fill="{StaticResource linearGradientBackground}"
  Stroke="Black"
  StrokeThickness="2" />

<Path
  Data="M10,100 C 60,0 100,200 150,100 z"
  Fill="{StaticResource linearGradientBackground}"
  Stroke="Black"
  StrokeThickness="2" >
  <Path.RenderTransform>
    <ScaleTransform ScaleX="3.0" ScaleY="3.0" />
  </Path.RenderTransform>
</Path>

해상도와 장치 독립적 그래픽에 대하여
스크린상에서 텍스트와 그래픽의 크기를 결정하는 두가지 시스템 요인이 있습니다. 바로 해상도(resolution)와 DPI입니다. 해상도는 스크린상에 나타날 픽셀의 수를 기술합니다. 해상도가 높아질 수록 픽셀은 작아지기 때문에 그래픽과 텍스트는 작게 나타납니다. 그래픽은 모니터를 1024 x 768로 설정할 때보다 1600 x 1200으로 설정할 때 더 작게 보일 것입니다.

다른 시스템 설정인 DPI는 스크린 인치(inch)당 픽셀의 크기를 기술합니다. 대부분의 윈도 시스템은 96 DPI를 가지고 있고 스크린 인치는 96 픽셀이라는 것을 의미합니다. DPI 설정을 증가시키는 것은 스크린 인치를 크게 하고 DPI를 감소시키는 것은 스크린 인치를 작게 합니다. 이것은 스크린 인치는 실제의 인치와 같은 크기가 아니라는 것을 의미합니다. 대부분의 시스템에서 대개 그렇습니다. DPI를 증가시키면, 스크린 인치의 크기가 증가되기 때문에 DPI맞춤(DPI-aware) 그래픽과 텍스트는 커집니다. DPI를 증가시키는 것은 특히 높은 해상도에서 텍스트 가독성을 높혀줍니다.

모든 애플리케이션이 DPI맞춤은 아닙니다. 어떤 것은 측정의 주단위로 하드웨어 픽셀을 사용합니다. 이런 애플리케이션에서 시스템 DPI를 변경하는 것은 아무런 효과도 없습니다. 많은 다른 애플리케이션은 폰트 크기를 기술하기 위해 DPI맞춤 단위를 사용하지만 다른 모든 것을 기술하는데에 픽셀을 사용합니다. DPI를 너무 작거나 너무 크게 하는 것은 애플리케이션의 레이아웃 문제를 일으키는 원인이 되기 때문에 애플리케이션의 텍스트는 시스템의 DPI 세팅에 따라 조절되지만 애플리케이션의 UI는 그렇지 않습니다.

이 문제는 WPF를 사용하여 개발된 애플리케이션에서 제거되었습니다. WPF는 하드웨어 픽셀 대신 측정의 주단위로써 장치 독립적인 픽셀을 사용하여 자동 스케일링을 지원합니다. 그래픽과 텍스트는 애플리케이션 개발자의 어떤 추가 작업 없이도 제대로 조절됩니다. 다음 그림은 WPF가 텍스트와 그래픽을 다른 DPI 설정에서 표시하는 방법을 보여줍니다.

다른 DPI 설정에서의 그래픽과 텍스트


VisualTreeHelper 클래스

VisualTreeHelper 클래스는 비주얼 객체 레벨에서 프로그래밍하기 위한 저수준(low-level) 기능을 제공하는 static 헬퍼 클래스이며, 고성능 사용자 정의 컨트롤 개발과 같은 매우 특이한 시나리오에서 유용합니다. 대부분의 경우에서 CanvasTextBlock과 같은 고수준(higer-level) WPF 프레임웍 객체는 매우 융통성있고 사용하기 쉽습니다.

충돌 테스팅
VisualTreeHelper 클래스는 기본 히트 테스트가 필요에 맞지 않을 경우 비주얼 객체상의 충돌 테스팅을 위한 메소드를 제공합니다. 컨트롤이나 그래픽 엘리먼트와 같은 객체의 영역 내에 지오메트리나 포인트 좌표값이 있는지 여부를 결정하기 위하여 VisualTreeHelper에서 HitTest 메소드를 사용할 수 있습니다. 예를 들어 원형의 지오메트리를 둘러싸는 사각형(bounding rectangle) 영역내에 마우스 클릭이 있었는지 여부를 결정하기 위해 히트 테스팅을 사용할 수 있습니다. 또한 직접 작성한 히트 테스트 계산 동작을 위해 기본 히트 테스팅 구현을 오버라이드하는 방법을 택할 수도 있습니다.

히트 테스팅에 관한 더 자세한 정보는 Hit Testing in the Visual Layer를 참고하십시오.

비주얼 트리 열거하기
VisualTreeHelper
클래스는 비주얼 트리의 멤버를 열거하는 기능을 제공합니다. (트리의) 부모를 얻기 위해 GetParent를 호출합니다. 자식을 얻거나 비주얼 객체의 자손을 가리키기 위해 GetChild 메소드를 호출합니다. 이 메소드는 지정된 인덱스에 있는 부모의 자식 Visual을 반환합니다.

다음 예제는 비주얼 객체의 모든 자손을 열거하는 방법을 보여줍니다. 이것은 비주얼 객체 계층 구조의 모든 렌더링 정보를 직렬화하고 싶다면 꼭 사용해야 할 기술입니다.

C#
// 비주얼 객체의 모든 자손을 열거.
static public void EnumVisual(Visual myVisual)
{
    for (int i = 0; i < VisualTreeHelper.GetChildrenCount(myVisual); i++)
    {
        // 지정된 인덱스 값의 자식 비주얼을 얻음.
        Visual childVisual = (Visual)VisualTreeHelper.GetChild(myVisual, i);

        // 자식 비주얼 객체로 처리 수행.

        // 자식 비주얼 객체의 자식을 열거(재귀 호출).
        EnumVisual(childVisual);
    }
}

대부분의 경우에서 로지컬 트리는 WPF 애플리케이션의 엘리먼트를 나타내는데 더 유용합니다. 비록 로지컬 트리를 직접적으로 수정하지 않을 지라도 이 애플리케이션의 뷰는 상속과 이벤트 라우팅을 이해하는데 유용합니다. 비주얼 트리와는 달리 로지컬 트리는 ListItem과 같은 비-비주얼 데이터 객체를 나타낼 수 있습니다. 로지컬 트리에 대한 더 자세한 정보는 Element Tree를 참고하십시오.

VisualTreeHelper 클래스는 비주얼 객체를 둘러싸는 사각형을 반환하는 메소드를 제공합니다. GetContentBounds를 호출하여 비주얼 객체를 둘러싸는 사각형을 반환할 수 있습니다. 또한 GetDescendantBound를 호출하여 비주얼 객체 자신을 포함한 모든 비주얼 객체를 둘러싸는 사각형을 반환할 수 있습니다. 다음 코드는 비주얼 객체와 모든 자신의 자손을 둘러싸는 사각형을 계산하는 방법을 보여줍니다.

C#
// 부모 비주얼 객체와 모든 자손을 둘러싸는 사각형을 반환.
Rect rectBounds = VisualTreeHelper.GetDescendantBounds(parentVisual);

See Also

Reference
Visual
VisualTreeHelper
DrawingVisual

Concepts
Hit Testing in the Visual Layer
Using DrawingVisual Objects
Tutorial: Hosting Visual Objects in a Win32 Application
Optimizing WPF Application Performance
신고
Posted by gongdo
MSDN : http://msdn2.microsoft.com/en-us/library/ms742562.aspx

WPF Graphics, Animation, and Media Overview


이 토픽은 애플리케이션에 그래픽, 변형 효과, 사운드 및 비디오를 추가할 수 있게 하는 WPF의 그래픽, 애니메이션 및 미디어 기능을 소개합니다.

WPF는 이 전에는 전문적인 라이브러리를 통해서만 가능했던 - 특히, Microsoft Windows Graphics Device Interface(GDI) 와 Microsoft Windows GDI+ - 고급 드로잉과 애니메이션 기능을 제공합니다. WPF는 이제 멀티미디어, 벡터 그래픽, 애니메이션 및 컨텐트 작성을 위한 통합된 지원을 제공하며 개발자가 쉽게 재밌는 사용자 인터페이스와 컨텐트를 만들수 있도록 합니다. Microsoft Visual Studio .NET이나 심지어 노트패드와 같은 텍스트 에디터를 사용할 수도 있습니다. 벡터 그래픽이나 복잡한 애니메이션을 만들 수 있고 애플리케이션에 미디어를 통합할 수 있습니다.

이 토픽은 다음 섹션을 담고 있습니다.
WPF에서의 그래픽와 멀티미디어의 새로운 점

WPF는 윈도 개발자에게 다음과 같은 이점을 갖는 새 그래픽 기능을 소개합니다.
  • 해상도(resolution)와 장치에 독립적인 그래픽.
    WPF 그래픽 시스템은 해상도와 장치에 종속적이지 않은 장치 독립적인 유닛을 사용합니다. 각 장치 독립적 픽셀은 시스템의 DPI(dots-per-inch) 세팅에 맞춰 자동적으로 조절(scale)합니다.
  • 향상된 정밀도.
    WPF 좌표계는 floats 대신 doubles를 사용합니다. 변형과 불투명도 값 또한 doubles를 사용하여 표현됩니다. WPF는 또한 더 넓은 색상 영역(scRGB)을 지원하고 서로 다른 색공간에서의 입력을 관리하는 통합된 지원을 제공합니다.
  • 고급 그래픽과 애니메이션 지원.
    WPF는 신(scene) 그래프를 관리함으로써 그래픽 프로그래밍을 단순화합니다. 더 이상 신 처리, 렌더링 루프 및 이중 선형 보간법(bilinear interpolation)에 대해 걱정할 필요가 없습니다. WPF는 애니메이션 시스템에 통합된 충돌 테스팅을 제공하고 완전한 알파 합성을 지원합니다.
  • 하드웨어 가속.
    WPF 그래픽 시스템은 CPU 사용량을 최소화 하기 위해 그래픽 하드웨어의 유리함을 취하도록 디자인되었습니다.
2-D 도형(Shapes)
WPF는 다음 그림과 같이 직사각형과 타원과 같은 일반적으로 사용되는 벡터 방식의 2-D 도형의 라이브러리를 제공합니다.
사용자 삽입 이미지
이 내부적인 WPF 도형은 단순한 도형이 아니라 대부분의 일반적인 컨트롤에서 기대하는 키보드 및 마우스 입력을 포함한 많은 기능을 구현하는 프로그래밍 가능한 요소입니다.

XAML

<Window

  xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"

  xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"

  x:Class="Window1" >

  <Ellipse Fill="LightBlue" MouseUp="ellipseButton_MouseUp" />

</Window>


C#

public partial class Window1 : Window

{

    void ellipseButton_MouseUp(object sender, MouseButtonEventArgs e)

    {

        MessageBox.Show("Me, a simple ellipse, was mouse clicked!");

    }

}


다음 그림은 전술한 XAML 마크업과 코드-비하인드의 출력을 보여줍니다.
사용자 삽입 이미지
더 자세한 정보는 Shapes and Basic Drawing in WPF Overview를 참고하십시오. 예제 샘플은 Shape Elements Samples를 참고하십시오.

2-D 기하(Geometries, 이하 지오메트리)
WPF가 제공하는 2-D 도형이 충분하지 않다면 지오메트리와 패스(path)를 위한 WPF 지원을 사용하여 직접 만들 수 있습니다. 다음 그림은 드로잉 브러쉬로 도형을 만들고 다른 WPF 엘리먼트로 클립하기 위해 지오메트리를 사용하는 방법을 보여줍니다.
사용자 삽입 이미지
더 자세한 정보는 Geometry Overview를 참고하고, 소개 샘플은 Geometries Sample을 참고하십시오.

2-D 효과
WPF는 다양한 효과를 생성하기 위해 사용할 수 있는 2-D 클래스 라이브러리를 제공합니다. WPF의 2-D 렌더링 능력은 UI 엘리먼트를 그레이디언트, 비트맵, 드로잉 및 비디오로 칠할(paint) 수 있는 능력을 제공하고 그것을 회전, 스케일링 및 비틀기를 사용하여 조작할 수 있습니다. 다음 그림은 WPF 브러쉬를 사용하여 얻을 수 있는 많은 효과의 예를 보여줍니다.
사용자 삽입 이미지
더 자세한 정보는 WPF Brushes Overview를 참고하고, 소개 샘플은 Brushes Sample을 참고하십시오.

3-D 렌더링
WPF는 더욱 확장된 레이아웃, UI와 데이터 시각화를 만들기 위해 2-D 그래픽 지원과 함께 통합되는 3-D 렌더링 기능의 세트를 제공합니다. 스펙트럼의 끝에서 WPF는 다음 그림에서 보여주는 것 처럼 3-D 도형의 표면상에 2-D 이미지를 그릴 수 있게 합니다.
사용자 삽입 이미지
더 자세한 정보는 3-D Graphics Overview를 참고하고 소개 샘플은 3-D Solids Sample을 참고하십시오.

애니메이션

애니메이션을 사용하여 컨트롤과 엘리먼트를 확대하고 흔들고 회전하고 페이드할 수 있으며, 재밌는 페이지 변형 등을 만들 수 있습니다. WPF가 대부분의 속성을 움직일(animate)수 있게 하기 때문에 대부분의 WPF 객체를 움직일 수 있을 뿐만 아니라 생성한 사용자 정의 객체도 WPF를 사용하여 움직일 수 있습니다.
사용자 삽입 이미지

더 자세한 정보는 Animation Overview를 참고하고, 소개 샘플은 Animation Example Gallery를 참고하십시오.

미디어

이미지, 비디오 및 오디오는 정보와 사용자 경험을 전달하는 최선의 방법입니다.

이미지
아이콘, 배경뿐만 아니라 애니메이션의 부분까지도 포함하는 이미지는 많은 애플리케이션의 핵심 부분입니다. 이미지를 사용할 필요가 자주있기 때문에 WPF는 다양한 방법으로 이미지를 포함한 작업을 할 수 있는 기능을 노출합니다. 다음 그림은 그 방법 중 하나를 보여줍니다.
사용자 삽입 이미지
더 자세한 정보는 Imaging Overview를 참고하고, 소개 샘플은 WPF Photo Viewer Demo를 참고하십시오.

비디오와 오디오
WPF 그래픽 기능의 핵심은 비디오와 오디오를 포함한 멀티미디어 작업을 위한 네이티브 지원을 제공하는 것입니다. 다음은 애플리케이션에 어떻게 미디어 플레이어를 삽입하는지 보여줍니다.

XAML

<MediaElement Source="media\numbers.wmv" Width="450" Height="250" />


MediaElement
는 비디오와 오디오 모두를 재생할 수 있고 사용자 정의 UI의 작성을 쉽게할 수 있는 충분한 확장성이 있습니다.

더 자세한 정보는 Multimedia Overview를 참고하고 소개 샘플은 Media Gallery를 참고하십시오.

See Also

Concepts
Shapes and Basic Drawing in WPF Overview
Painting with Solid Colors and Gradients Overview
Painting with Images, Drawings, and Visuals
Animation Overview
신고
Posted by gongdo
MSDN : http://msdn2.microsoft.com/en-us/library/ms742196.aspx

Graphics Rendering Tiers


렌더링 단계(Rendering tier)는 WPF 애플리케이션을 실행하는 장치를 위한 그래픽 하드웨어 능력과 성능의 레벨을 정의합니다.

이 토픽은 다음 섹션을 담고 있습니다.
그래픽 하드웨어

렌더링 단계 레벨에 가장 큰 영향을 주는 그래픽 하드웨어의 기능(feature)은 다음과 같습니다.
  • 비디오 램 ; 그래픽 하드웨어에 장착된 비디오 메모리의 합계로써 복합적인 그래픽에 사용될 수 있는 버퍼의 크기와 수를 결정합니다.
  • 픽셀 셰이더 ; 픽셀 셰이더는 픽셀 기반의 효과를 계산하는 그래픽 처리 기능입니다. 표시되는 그래픽의 해상도에 따라서 각 디스플레이 프레임을 위해 처리될 필요가 있는 수백만 픽셀이 있을 수 있습니다.
  • 버텍스(vertex) 셰이더 ; 객체의 버텍스 데이터상에 있는 수학적인 연산 동작을 수행하는 그래픽 처리 기능입니다.
  • 멀티텍스쳐 지원 ; 멀티텍스쳐 지원은 3D 그래픽 객체상에서 블렌딩 연산 도중 두개 혹은 그 이상으로 구분되는 텍스쳐를 적용하는 능력을 말합니다. 멀티텍스쳐 지원의 정도는 그래픽 하드웨어상의 멀티텍스쳐 유닛의 수에 따라 결정됩니다.
픽셀 셰이더, 버텍스 셰이더 및 멀티텍스쳐 기능은 특정 DirectX 버전 레벨을 정의하는데 사용되고 WPF에서 렌더링 단계의 차이를 정의합니다.

렌더링 단계 정의

그래픽 하드웨어에서 제공되는 기능은 WPF 애플리케이션의 렌더링 능력을 결정합니다. WPF 시스템은 다음의 세 렌더링 단계를 정의합니다.

  • 렌더링 단계 0 ; 그래픽 하드웨어 가속 없음. DirectX 버전 레벨은 버전 7.0보다 낮습니다.
  • 렌더링 단계 1 ; 부분적인 그래픽 하드웨어 가속. DirectX 버전 레벨은 버전 7.0과 같거나 더 높고 버전 9.0보다 낮습니다.
  • 렌더링 단계 2 ; 대부분의 그래픽 기능을 사용하는 그래픽 하드웨어 가속. DirectX 버전 레벨은 버전 9.0과 같거나 더 높습니다.
Tier 속성은 애플리케이션 런타임에 렌더링 단계를 얻을 수 있게 하며, 개발자가 장치에 특정 하드웨어 가속된 그래픽 기능을 지원하는지를 결정할 수 있게 합니다. 그러므로 애플리케이션은 장치에 의해 지원되는 렌더링 단계에 따라서 런타임에 다른 코드 경로를 취할 수 있습니다.

렌더링 단계 0
렌더링 단계 0은 장치상에 애플리케이션을 위한 그래픽 하드웨어 가속 지원이 없다는 것을 의미합니다. 이 단계 레벨에서 개발자는 모든 그래픽이 하드웨어 가속 없이 소프트웨어에 의해 그려진다고 가정해야 합니다. 이 단계의 기능성은 DirectX 버전 7.0 미만과 일치합니다.

렌더링 단계 1
렌더링 단계 1은 비디오 카드에서 일부 그래픽 하드웨어 가속이 가능하다는 것을 의미합니다. 이것은 DirectX 버전 7.0 이상과 9.0 미만과 일치합니다.

다음 기능과 능력은 렌더링 단계 1에서 하드웨어 가속됩니다.

2D 렌더링 ; 대부분의 2D 그리기가 지원됩니다.
3D 래스터화 ; 대부분의 3D 래스터화가 지원됩니다. 그러나 WPF는 버텍스 컬러로 하드웨어에 전달된 버텍스 조도를 계산하는데 소프트웨어를 사용할 것입니다.
3D 비등방성 필터링(anisotrophic) ; 렌더링 단계가 1이상이면 WPF는 3D 컨텐트를 그릴 때 비등방성 필터링 사용을 시도합니다. 비등방성 필터링은 카메라의 주의에서 멀리 있고 급한 각도를 이루는 표면상의 이미지 품질을 높이는 것을 말합니다.
3D MIP 매핑 ; 렌더링 단계가 1이상이면 WPF는 3D 컨텐트를 그릴 때 MIP 매핑 사용을 시도합니다. MIP 매핑은 텍스쳐가 Viewport3D에 있는 뷰보다 작은 필드를 차지할 경우 텍스쳐의 품질을 향상시킵니다. (※역주 : 비등방성 필터링이나 MIP매핑 등의 정의는 3D 그래픽 영역에 속하며 위키 사전등을 참조하도록 합니다. 비등방성 필터링(테크노아), MIP Map(위키)  )

다음 기능과 능력은 렌더링 단계 1에서는 하드웨어 가속되지 않습니다.
비트맵 효과 ; 시각적 표현의 비트맵 효과는 하드웨어 가속 없이 그려지도록 강제됩니다.
출력된 컨텐트 ; 모든 출력된 컨텐트는 WPF 소프트웨어 파이프라인을 사용하여 그려집니다.
RenderTargetBitmap 객체를 사용하여 래스터화된 컨텐트 ; 모든 컨텐트는 RenderTargetBitmapRender 메소드를 사용하여 그려집니다.
TileBrush를 사용한 격자 컨텐트 ; TileBrushTileModeTile로 설정된 모든 격자 컨텐트.
그래픽 하드웨어의 최대 텍스쳐 크기를 초과한 표면 ; 대부분의 그래픽 카드는 2048 x 2048 또는 4096 x 4096 픽셀보다 큰 크기의 표면을 지원하지 않습니다.
그래픽 하드웨어의 메모리를 초과하는 비디오 램을 요청하는 모든 명령 ; Windows SDK에 포함된 Preforator 툴을 사용하여 애플리케이션의 비디오 램 사용량을 모니터할 수 있습니다.
레이어드(layered) 윈도 ; 레이어드 윈도는 WPF 애플리케이션이 비사각형 윈도의 화면에 컨텐트를 그릴 수 있게 합니다. 윈도 Vista에서는 레이어드 윈도가 하드웨어 가속됩니다. 윈도 XP와 같은 다른 시스템에서는 레이어드 윈도는 하드웨어 가속 없이 소프트웨어에 의해 그려집니다. 다음의 Window 속성을 세팅함으로써 WPF에서 레이어드 윈도를 사용할 수 있습니다.
원형 그레디언트 ; 모든 RadialGradientBrush의 사용.
3D 조명 계산 ; WPF는 버텍스당 조명으로 작동하며 이것은 조도가 메쉬에 적용되는 각 마테리얼을 위해 버텍스마다 계산되어야 한다는 것을 의미합니다. 단계 1에서 이 계산은 소프트웨어에 의해 작동됩니다. 단계 2에서는 이 계산이 하드웨어에 의해 작동됩니다.
텍스트 렌더링 ; 서브-픽셀 폰트 렌더링은 그래픽 하드웨어상의 픽셀 셰이더를 사용할 수 있습니다.
3D 안티-앨리에싱 ; 모든 3D 안티-앨리어싱의 사용.

다음 그래픽 하드웨어 기능은 렌더링 단계 1을 정의합니다.
DirectX 버전 ; 7.0 이상이고 9.0 미만이어야 합니다.
비디오 램 ; 30MB 이상이어야 합니다.
멀티텍스쳐 유닛 ; 2이상의 유닛이 있어야 합니다.

다음 표는 렌더링 단계1을 지원하는 일반적인 그래픽 카드의 목록입니다.

ATI ; Radeon 모델 : 256, 7000, 7500, 8500, 9000, 9100, 9200 및 9250
Intel ; 인텔 Extreme Graphics 모델 : 845G, 845GE, 845GL 및 845GV
        인텔 Extreme Graphics II 모델 : 852GME, 855GM, 855GME, 865G 및 865GV
NVidia ; GeForce 256
            GeForce2 모델 : GTS, MX, MX100, MX200, MX400, Pro, Ti 및 Ultra
            GeForce3 모델 : Ti200 및 Ti500
            GeForce4 모델 : MX420, MX440, MX460, MX4000, Ti4200, Ti4400, Ti4600 및 Ti4800
 
렌더링 단계2
렌더링 단계 2는 WPF의 그래픽 피추어 대부분이 가용 시스템 리소스가 고갈되지 않도록 하드웨어 가속을 사용할 필요가 있습니다. 이것은 9.0 이상의 DirectX 버전과 일치합니다.

다음 기능 및 기능은 렌터링 단계2를위해 하드웨어 가속됩니다.
단계 1 기능 ; 모든 단계 1의 기능을 포함합니다.
원형 그레이디언트 ; 지원될지라도 큰 객체상에서의 RadialGradientBrush의 사용은 피하십시오.
3D 조명 계산 ; WPF는 버텍스당 조명으로 동작하며, 이것은 조도가 메쉬에 적용될 각 마테리얼을 위한 각각의 버텍스에서 계산되어야 한다는 것을 의미합니다. 계층 1에서 이 계산은 소프트웨어에 의해 동작합니다. 계층 2에서 이 계산은 하드웨어에서 동작합니다.
텍스트 렌더링 ; 서브-픽셀 폰트 렌더링은 그래픽 하드웨어 상의 픽셀 셰이더를 사용할 수 있습니다.
3D 안티-앨리어싱 ; 3D 안티-앨리어싱은 윈도 Vista에서만 지원됩니다.

다음 기능과 능력은 렌터링 단계 2에서 하드웨어 가속되지 않습니다.
비트맵 효과 ; 시각적 표현의 비트맵 효과는 하드웨어 가속 없이 그려지도록 강제됩니다.
출력된 컨텐트 ; 모든 출력된 컨텐트는 WPF 소프트웨어 파이프라인을 사용하여 그려집니다.
RenderTargetBitmap 객체를 사용하여 래스터화된 컨텐트 ; 모든 컨텐트는 RenderTargetBitmap의 Render 메소드를 사용하여 그려집니다.
TileBrush를 사용한 격자 컨텐트 ; TileBrush의 TileMode가 Tile로 설정된 모든 격자 컨텐트.
그래픽 하드웨어의 최대 텍스쳐 크기를 초과한 표면 ; 대부분의 그래픽 카드는 2048 x 2048 또는 4096 x 4096 픽셀보다 큰 크기의 표면을 지원하지 않습니다.
그래픽 하드웨어의 메모리를 초과하는 비디오 램을 요청하는 모든 명령 ; Windows SDK에 포함된 Preforator 툴을 사용하여 애플리케이션의 비디오 램 사용량을 모니터할 수 있습니다.
레이어드(layered) 윈도 ; 레이어드 윈도는 WPF 애플리케이션이 비사각형 윈도의 화면에 컨텐트를 그릴 수 있게 합니다. 윈도 Vista에서는 레이어드 윈도가 하드웨어 가속됩니다. 윈도 XP와 같은 다른 시스템에서는 레이어드 윈도는 하드웨어 가속 없이 소프트웨어에 의해 그려집니다. 다음의 Window 속성을 세팅함으로써 WPF에서 레이어드 윈도를 사용할 수 있습니다.
  • WindowStyle = None
  • AllowsTransparency = true
  • Transparent
다음 그래픽 하드웨어 기능은 렌더링 단계 2를 정의합니다.

DirectX 버전 ; 9.0 이상이어야 합니다.
비디오 램 ; 120MB 이상이어야 합니다.
픽셀 셰이더 ; 버전 2.0 이상이어야 합니다.
버텍스 셰이더 ; 버전 2.0 이상이어야 합니다.
멀티텍스쳐 유닛 ; 유닛의 수가 4 이상이어야 합니다.

다음 표는 렌더링 단계 2를 지원하는 일반적인 그래픽 카드의 목록입니다.
ATI ; Radeon 모델 : 9550, 9600, 9800 및 X-시리즈
Intel ; 인텔 GMA900 모델 : 915G
         인텔 GMA950 모델 : 945G
NVidia ; Geforce FX-시리즈, 6xxx-시리즈 및 7xxx-시리즈

다른 리소스

다음 리소스는 WPF 애플리케이션의 성능 특성을 분석하는데 도움을 줄 수 있습니다.

그래픽 렌더링 레지스트리 설정
WPF는 WPF 렌더링을 제어하기 위해 네가지 레지스트리 설정을 제공합니다.

하드웨어 가속 옵션 비활성화 ; 하드웨어 가속을 활성화할지 지정합니다.
최대 멀티샘플 값 ; 3D 컨텐트 안티-앨리어싱을 위한 멀티샘플링의 정도를 지정합니다.
비디오 드라이버 날짜 요구사항 설정 ; 2004년 11월 이전에 공개된 드라이버에서는 시스템이 하드웨어 가속을 비활성화할지 지정합니다.
래스터라이저 참조 사용 옵션 ; WPF가 래스터라이저 참조를 사용해야 하는지 지정합니다.

이 세팅은 WPF 레지스트리 설정을 어떻게 참조하는지 아는 모든 외부 설정 유틸리티에 의해 접근될 수 있습니다. 이 설정은 또한 윈도 레지스트리 편집기를 사용함으로써 값을 직접 접근하여 만들거나 변경할 수 있습니다. 더 자세한 정보는 Graphics Rendering Registry Settings를 참고하십시오.

WPF 성능 분석 툴
WPF는 애플리케이션의 런타임 동작 분석과 적용 가능한 성능 최적화의 종류를 결정하는 것을 가능케 하는 성능 분석 툴 스위트(suite)를 제공합니다. 다음 표는 Windows SDK 툴인 WPFPerf에 포함된 다섯개의 성능 분석 툴을 열거합니다.

EventTrace ; 이벤트를 분석하고 이벤트 로그 파일을 생성하는데 사용합니다.
Perforator ; 렌더링 동작을 분석하는데 사용합니다.
Trace Viewer ; WPF 사용자 인터페이스 포맷의 Event Tracing for Windows(ETW) 로그 파일을 기록하고, 표시하고 보여줍니다.
Visual Profiler ; 시각적인 트리에서 엘리먼트 별로 레이아웃과 이벤트 핸들링과 같은 WPF 서비스의 사용을 분석하는데 사용합니다.
Working Set Viewer ; 애플리케이션의 working set 특성을 분석하는데 사용합니다.

Visual Profiler 툴 스위트는 성능 데이터의 풍부한 그래피컬 뷰를 제공합니다. 아래의 스크린샷은 Visual Profiler의 CPU Usage 섹션이 객체의 렌더링이나 레이아웃 같은 WPF 서비스의 사용에 대한 정확한 분석을 제공합니다.

Visual Profiler 화면 표시
사용자 삽입 이미지

WPF 성능 툴에 대한 더 자세한 정보는 Performance Profiling Tools for WPF를 참고하십시오.

DirectX 진단 툴
DirectX 진단 툴인 Dxdiag.exe는 DiretX와 관련된 주제의 문제 해결을 돕도록 디자인되었습니다. DiretX 진단 툴의 기본 설치 경로는 \Windows\System32 입니다.

DirectX 진단 툴을 실행하면 메인 윈도는 DirectX와 관련된 정보를 표시하고 진단하도록 하는 탭의 세트를 적재합니다. 예를 들어 System 탭은 컴퓨터에 관한 시스템 정보와 컴퓨터에 설치되어 있는 DirectX의 버전을 제공합니다.

DirectX 진단 툴 메인 윈도
사용자 삽입 이미지

See Also

Reference
RenderCapability
RenderOptions

Concepts
Optimizing WPF Application Performance
Graphics Rendering Registry Settings

Other Resources
Performance Profiling Tools for WPF
신고
Posted by gongdo
MSDN : http://msdn2.microsoft.com/en-us/library/aa969773.aspx

Dialog Boxes Overview

일반적으로 독립 애플리케이션은 시각적인 데이터 및 데이터와 상호작용하기 위한 기능을 노출하는 메인 윈도를 가집니다. 예를 들어 워드 프로세서 애플리케이션은 문서를 시각화하고, 파일 관리 및 문서와 상호작용하기 위한 편집 기능을 노출합니다.

단순하지 않은 애플리케이션의 일반적인 라이프 사이클의 한 부분으로 메인 윈도는 사용자에게서 정보를 수집하거나 표시하기 위해 하나 이상의 이차적인 윈도를 사용자에게 보여줄 것입니다. 이차적인 윈도는 다이얼로그 박스(dialog boxes, ※역주 : 일반적으로 대화 상자라고 하지만 다이얼로그 박스로 그대로 사용하였습니다.)라고 알려져 있고, 모덜(modal)과 모덜리스(modeless)의 두가지 종류가 있습니다.

모덜 다이얼로그 박스는 사용자에게 작업을 완료하기 위해 필요한 추가적인 정보를 보여주거나 보통 그것이 열려 있는 동안 다른 윈도의 활성화를 막기 위해 사용됩니다. 예를 들어 사용자가 워드 프로세서에서 문서를 열고 싶다면, 애플리케이션은 사용자가 열기를 원하는 파일의 이름을 물을 것입니다. 사용자가 이름을 제공해주기 전까지는 문서를 열 수 없기 때문에 다이얼로그 박스는 사용자가 이름을 입력하여 다이얼로그 박스를 확인(accept)하거나 보통 Cancel 버튼을 눌러 다이얼로그 박스를 취소하기를 기다려야 합니다.

한편, 모덜리스 다이얼로그 박스는 그것이 열려있는 동안 다른 윈도의 활성화를 막지 않습니다. 예를 들어 사용자가 문서내에서 부분적인 단어의 존재를 찾고 싶을 때 메인 윈도는 사용자가 찾고 있는 단어를 묻는 다이얼로그 박스를 열 것입니다. 그러나, 단어를 찾는 것은 문서 편집을 막지 않으므로 모덜이 되어야 할 필요가 없습니다. 모덜리스 다이얼로그 박스는 보통 Close 버튼을 클릭하여 닫습니다.

WPF는 메시지 박스, 커먼(common) 다이얼로그 박스 및 사용자 정의 다이얼로그 박스와 같은 몇 가지 다이얼로그 박스의 종류를 만들 수 있게 해줍니다. 이 토픽은 각각에 대해 다루며, Dialog Box Sample은 해당 예제를 제공합니다.

이 토픽은 다음과 같은 섹션을 담고 있습니다.

메시지 박스

메시지 박스는 정보를 보여주거나 사용자가 결정을 할 수 있도록 하기 위해 사용되는 간단한 다이얼로그 박스입니다. 다음 그림은 정보를 표시하고 사용자로부터 응답을 유도하는 메시지 박스를 나타냅니다.
사용자 삽입 이미지

메시지 박스를 만들기 위해,
MessageBox 클래스를 사용합니다. MessageBox는 다음과 같은 코드를 사용하여 메시지 박스 내용, 제목, 아이콘 및 버튼들을 설정할 수 있게합니다.

C#
// Configure the message box
string messageBoxText = "This document needs to be saved ... .";
string caption = "Word Processor";
MessageBoxButton button = MessageBoxButton.YesNoCancel;
MessageBoxImage icon = MessageBoxImage.Warning;

메시지 박스를 보여주기 위해, 다음과 같이 static Show 메소드를 호출해야 합니다.

C#
// Display message box
MessageBox.Show(messageBoxText, caption, button, icon);

사용자가 클릭한 버튼을 검출하고 그에 맞는 응답을 하기 위해, 다음과 같이 메시지 박스의 결과를 받고 처리할 수 있습니다.

C#
// Display message box
MessageBoxResult messageBoxResult = MessageBox.Show(messageBoxText, caption, button, icon);
// Process message box results
switch (messageBoxResult)
{
    case MessageBoxResult.Yes: // Save document and exit
        SaveDocument();
        break;
    case MessageBoxResult.No: // Exit without saving
        break;
    case MessageBoxResult.Cancel: // Don't exit
        e.Cancel = true;
        break;
}

한 가지 중요한 MessageBox의 기능은 부분적으로 신뢰(partial trust)된 상태에서 동작하는 XAML 브라우저 애플리케이션(XBAPs)에서도 보여줄 수 있다는 것입니다(WPF Security를 참고).

메시지 박스 사용에 관한 더 자세한 정보는 MessageBox, MessageBox Sample 또는 Dialog Box Sample에서 찾을 수 있습니다.

커먼 다이얼로그 박스

메시지 박스가 유용한 정보를 보여주고 사용자에게 선택을 제공하는 동안, 대부분의 다이얼로그 박스는 일반적으로 어떤 버튼이 눌렸는가 보다는 더 자세한 정보를 사용자로부터 수집할 필요가 있습니다.

윈도는 파일 열기, 파일 저장하기 및 인쇄하기와 같이 모든 애플리케이션에서 공통적인 다양한 다이얼로그 박스를 구현합니다. 이것은 모든 애플리케이션이 사용하므로 커먼 다이얼로그 박스로 알려져 있습니다. 따라서, 이것은 애플리케이션 간의 일관성 있는 사용자 경험을 제공하는데 도움이 됩니다.

WPF는 독립 애플리케이션에서 사용할 수 있도록 관리된 클래스로 공통 파일 열기, 파일 저장 및 인쇄 다이얼로그 박스를 캡슐화합니다. 이 토픽은 각각의 개관을 제공합니다.

파일 열기 다이얼로그
다음 그림에서 보여주는 것과 같은 파일 열기 다이얼로그 박스는 파일 열기 기능에서 사용자가 열기를 원하는 파일명을 얻기 위해 사용됩니다.
사용자 삽입 이미지

공통 파일 열기 다이얼로그 박스는 OpenFileDialog 클래스로 구현되고, 다음 코드는 어떻게 생성, 설정 및 보여주고, 어떻게 결과를 처리하는지를 보여줍니다.

C#
void OpenDocument()
{
    // 파일 열기 다이얼로그 박스를 설정
    OpenFileDialog dlg = new OpenFileDialog();
    dlg.FileName = "Document"; // 기본 파일명
    dlg.DefaultExt = ".wpf"; // 기본 확장자
    dlg.Filter = "Word Processor Files (.wpf)|*.wpf"; // 확장 파일 필터

    // Show open file dialog box
    Nullable<bool> result = dlg.ShowDialog();

    // Process open file dialog box results
    if (result == true)
    {
        // Open document
        string filename = dlg.FileName;
    }
}

파일 열기 다이얼로그 박스에 대한 더 자세한 정보는 Microsoft.Win32.OpenFileDialog를 참고합니다.

OpenFileDialog는 부분적으로 신뢰되어 동작중인 애플리케이션에서 파일명을 안전하게 얻는데 사용할 수 있습니다(WPF Security를 참고). 예제는 Safe File Upload from an XBAP Sample을 참고합니다.

파일 저장 다이얼로그 박스
다음 그림에서 보여주는 것과 같은 파일 저장 다이얼로그 박스는 파일 저장 기능에서 사용자가 저장을 원하는 파일명을 얻기 위해 사용됩니다.
사용자 삽입 이미지

공통 파일 저장 다이얼로그 박스는 SaveFileDialog 클래스로 구현되고, 다음 코드는 어떻게 생성, 설정 및 보여주고, 어떻게 결과를 처리하는지를 보여줍니다.

C#
void SaveDocument()
{
    // 파일 저장 다이얼로그 박스 설정
    SaveFileDialog dlg = new SaveFileDialog();
    dlg.FileName = "Document"; // 기본 파일명
    dlg.DefaultExt = ".wpf"; // 기본 파일 확장자
    dlg.Filter = "Word Processor Files (.wpf)|*.wpf"; // 확장 파일 필터

    // Show save file dialog box
    Nullable<bool> result = dlg.ShowDialog();

    // Process save file dialog box results
    if (result == true)
    {
        // Save document
        string filename = dlg.FileName;
    }
}

파일 저장 다이얼로그 박스에 대한 더 자세한 정보는 Microsoft.Win32.SaveFileDialog를 참고합니다.

인쇄 다이얼로그 박스
다음 그림에서 보여주는 것과 같은 인쇄 다이얼로그 박스는 인쇄 기능에서 사용자가 출력을 원하는 파일에 대한 프린터 선택 및 설정을 위해 사용됩니다.
사용자 삽입 이미지

공통 인쇄 다이얼로그 박스는 PrintDialog 클래스로 구현되고, 다음 코드는 어떻게 생성, 설정 및 보여주는지를 보여줍니다.

C#
void PrintDocument()
{
    // Configure printer dialog box
    PrintDialog dlg = new PrintDialog();
    dlg.PageRangeSelection = PageRangeSelection.AllPages;
    dlg.UserPageRangeEnabled = true;

    // Show save file dialog box
    Nullable<bool> result = dlg.ShowDialog();

    // Process save file dialog box results
    if (result == true)
    {
        // Print document
    }
}

인쇄 다이얼로그 박스에 대한 더 자세한 정보는 System.Windows.Controls.PrintDialog를 참고합니다. WPF에서 인쇄하기에 관한 자세한 논의는 Printing Overview를 참고합니다.

사용자 정의 다이얼로그 박스

메시지 박스보다 복잡하고, 커먼 다이얼로그 박스에 의해 지원되지 않는 다이얼로그 박스가 필요할 때, 직접 다이얼로그 박스를 만들 필요가 있습니다. WPF는 모덜과 모덜리스 다이얼로그 박스 모두 Window를 사용하여 만들 수 있게 합니다.

모덜 사용자 정의 다이얼로그 박스 만들기
MarginsDialogBox와 같은 모덜 다이얼로그 박스는 시각적인 요구사항과 동작의 세트를 가진 다음 그림에서 보여주고 있습니다.
사용자 삽입 이미지

이 토픽은 이를 설명하고 다이얼로그 박스 구현의 기본 구성요소를 제시합니다.

모덜 다이얼로그 박스 설정하기
전형적인 다이얼로그 박스를 위한 사용자 인터페이스는 다음과 같은 몇 가지 주요 동작을 가집니다.
  • 사용자가 다이얼로그 박스를 닫고 처리를 계속하기 위해(OK) 클릭할 Button. 이 버튼은 또한 자신의 IsDefault 속성을 true로 설정하기 위해 필요합니다. 이것은 사용자가 ENTER 키를 눌러 다이얼로그 박스를 확인(accept)할 수 있게 합니다.
  • 사용자가 다이얼로그 박스를 닫고 취소하는 기능을 위해(Cancel) 클릭할 Button. 이 버튼은 자신의 IsCancel 속성을 true로 설정하기 위해 필요합니다. 이것은 사용자가 ESC 키를 눌러 다이얼로그 박스를 취소할 수 있게 합니다.
  • 타이틀바에 Close 버튼 보여주기.
  • Icon 보여주기.
  • 최소화, 최대화 및 이전 크기로 버튼 보여주기.
  • 다이얼로그 박스의 시스템 메뉴에 최소화, 최대화, 이전 크기로 및 닫기 버튼 보여주기.
  • 다이얼로그 박스를 연 윈도의 한가운데에 열기.
  • 다이얼로그 박스는 너무 작게 되는 것을 막기 위해 가능하다면 크기 조절이 가능해야하며, 사용자에게 유용한 기본 크기를 제공하기 위해 기본적인 크기와 최소 크기를 각각 설정할 필요가 있습니다.
Dialog Box Sample에서와 같이 Margin 다이얼로그 박스 같은 Window를 사용한 설정을 가진 다이얼로그 박스를 만들 수 있습니다.

XAML
<Window
    xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
    xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
    x:Class="MarginsDialogBox"
    xmlns:local="clr-namespace:DialogBoxSample"
    Title="Margins"
    Height="190" Width="300"
    MinHeight="190" MinWidth="300"
    ResizeMode="CanResizeWithGrip"
    ShowInTaskbar="False"
    WindowStartupLocation="CenterOwner"
    FocusManager.FocusedElement="{Binding ElementName=leftMarginTextBox}">

  <Grid>

    <!-- Grid column and row definitions -->

    <Grid.Resources>
      <!-- Grid column and row definitions -->
      ...
    </Grid.Resources>

    <!-- Grid column and row definitions -->
    <Grid.ColumnDefinitions>
      <!-- Column definitions -->
      ...
    </Grid.ColumnDefinitions>

    <Grid.RowDefinitions>
      <!-- Row definitions -->
      ...
    </Grid.RowDefinitions>

    <!-- Left Margin -->
    <Label Grid.Column="0" Grid.Row="0">Left Margin:</Label>
    <TextBox Name="leftMarginTextBox" Grid.Column="1" Grid.Row="0">
    </TextBox>

    <!-- Top Margin -->
    <Label Grid.Column="0" Grid.Row="1">Top Margin:</Label>
    <TextBox Name="topMarginTextBox" Grid.Column="1" Grid.Row="1">
    </TextBox>

    <!-- Right Margin -->
    <Label Grid.Column="0" Grid.Row="2">Right Margin:</Label>
    <TextBox Name="rightMarginTextBox" Grid.Column="1" Grid.Row="2">
    </TextBox>

    <!-- Bottom Margin -->
    <Label Grid.Column="0" Grid.Row="3">Bottom Margin:</Label>
    <TextBox Name="bottomMarginTextBox" Grid.Column="1" Grid.Row="3">
    </TextBox>

    <!-- Accept or Cancel -->
    <StackPanel Grid.Column="0" Grid.ColumnSpan="2" Grid.Row="4">
      <Button Name="okButton" IsDefault="True">OK</Button>
      <Button Name="cancelButton" IsCancel="True">Cancel</Button>
    </StackPanel>

  </Grid >
</Window>

다이얼로그 박스를 위한 사용자 경험은 또한 메뉴바로 확장됩니다. (※역주 : 이 문장은 의미를 잘 모르겠습니다. When a function that shows a dialog box to collect user information, the menu item that exposes that function will have an ellipses in its header, as shown here: )
(※역주 : 원문에는 C#이라고 나와있지만 XAML 코드입니다.)

XAML
<Window ... >
  ...
    <MenuItem 
      Name="formatMarginsMenuItem"
      Header="_Margins..."
      Click="formatMarginsMenuItem_Click" />
  ...
</Window >

About 다이얼로그 박스처럼, 오직 정보만을 표시하는 다이얼로그 박스가 열렸을 때, 이에 대응하는 메뉴 아이템은 타원을 필요로하지 않습니다.

모덜 다이얼로그 박스 열기
사용자가 다이얼로그 박스를 보여주기 위해 메뉴 아이템을 선택하였을 때, 다이얼로그 박스는 다른 메시지 박스와 커먼 다이얼로그 박스처럼 인스턴스화 되고, 설정되고, 열려야 합니다.

다음 코드는 어떻게 다이얼로그 박스를 인스턴스화 하는지 보여줍니다.

C#
public partial class MainWindow : Window
{
    ...
    void formatMarginsMenuItem_Click(object sender, RoutedEventArgs e)
    {
        // Instantiate the dialog box
        MarginsDialogBox dlg = new MarginsDialogBox();
    }
    ...
}

다음으로, 다이얼로그 박스는 사용되기 전에 설정될 필요가 있습니다.

C#
public partial class MainWindow : Window
{
    ...
    void formatMarginsMenuItem_Click(object sender, RoutedEventArgs e)
    {
        // Instantiate the dialog box
        MarginsDialogBox dlg = new MarginsDialogBox();

        // Configure the dialog box
        dlg.Owner = this;
        dlg.DocumentMargin = this.documentTextBox.Margin;
    }
    ...
}

여기에서, 코드는 기본 정보를 다이얼로그 박스로 전달합니다. 또한 System.Windows.Window.Owner 속성을 다이얼로그 박스를 보여주는 윈도의 레퍼런스로 설정합니다. 일반적으로, 모든 다이얼로그 박스를 위한 공통적인 윈도 상태-관련(state-related) 동작(behavior)를 제공하기 위해 항상 다이얼로그 박스의 소유자를 설정해야 합니다(WPF Windows Overview 참고).

노트:
반드시 다이얼로그 박스를 위한 유저 인터페이스(UI) 자동화를 지원하는 소유자를 제공해야 합니다(UI Automation Overview 참고).

일단 다이얼로그 박스가 설정되면, 그것은 보여줄 준비가 된 것입니다. 모덜 다이얼로그 박스는 다음과 같이 ShowDialog 메소드를 호출하여 보여지게 됩니다.

C#
public partial class MainWindow : Window
{
    ...
    void formatMarginsMenuItem_Click(object sender, RoutedEventArgs e)
    {
        // Instantiate the dialog box
        MarginsDialogBox dlg = new MarginsDialogBox();

        // Configure the dialog box
        dlg.Owner = this;
        dlg.DocumentMargin = this.documentTextBox.Margin;

        // Open the dialog box modally
        dlg.ShowDialog();

    }
    ...
}

ShowDialog는 다이얼로그 박스를 모덜로 열고, 그 후 사용자는 다이얼로그 박스를 확인(accept)하거나 취소(cancel)하기 전까지 데이터를 입력합니다.

사용자 제공 데이터 유효성 검사
일단 다이얼로그 박스가 열리고 사용자가 데이터를 입력하면, 다이얼로그 박스는 다음과 같은 세가지 이유로 사용자의 입력이 유효한지 여부를 확인할 책임이 있습니다.
  • 보안상의 관점에서, 모든 입력은 유효해야 합니다.
  • 애플리케이션의 관점에서, 데이터 유효성 검사는 잠재적으로 예외를 던질 수 있는 코드에 의한 처리로부터 잘못된 자료를 방지합니다.
  • 사용자 경험의 관점에서, 다이얼로그 박스는 어떤 데이터가 잘못 입력되었는지를 보여줌으로서 사용자를 도울 수 있습니다.
WPF에서 바운드된 컨트롤을 유효화하기 위해, 유효성 규칙(validation rule)을 만들고 그것을 바인딩과 연결시킬 필요가 있습니다.

유효성 규칙은 ValidationRule을 상속하는 사용자 정의 클래스입니다. 다음 예제는 바운드 값이 double이고 지정된 범위내에 있는지를 검사하는 MarginValidationRule을 보여줍니다.

C#
using System.Windows.Controls;
public class MarginValidationRule : ValidationRule
{
    double minMargin;
    double maxMargin;

    public double MinMargin
    {
        get { return this.minMargin; }
        set { this.minMargin = value; }
    }

    public double MaxMargin
    {
        get { return this.maxMargin; }
        set { this.maxMargin = value; }
    }

    public override ValidationResult Validate(object value, System.Globalization.CultureInfo cultureInfo)
    {
        double margin;

        // Is a number?
        if (!double.TryParse((string)value, out margin))
        {
            return new ValidationResult(false, "Not a number.");
        }

        // Is in range?
        if ((margin < this.minMargin) || (margin > this.maxMargin ))
        {
            string msg = string.Format("Margin must be between {0} and {1}.", this.minMargin, this.maxMargin);
            return new ValidationResult(false, msg);
        }

        // Number is valid
        return new ValidationResult(true, null);
    }
}

바운드 값을 유효화하기 위해, 위의 코드에서 보여주는 것 처럼 Validate를 오버라이드하고 적절한 ValidationResult를 반환해야 합니다.

유효성 규칙을 바운드 컨트롤과 연결하기 위해, 다음과 같은 마크업을 사용합니다.

XAML
<Window ... >
    ...
    <!-- Left Margin -->
    <Label Grid.Column="0" Grid.Row="0">Left Margin:</Label>
    <TextBox Name="leftMarginTextBox" Grid.Column="1" Grid.Row="0">
      <TextBox.Text>
        <Binding Path="Left" UpdateSourceTrigger="PropertyChanged">
          <Binding.ValidationRules>
            <local:MarginValidationRule MinMargin="0" MaxMargin="10" />
          </Binding.ValidationRules>
        </Binding>
      </TextBox.Text>
    </TextBox>
    ...
</Window>

WPF는 데이터가 바운드 컨트롤로 입력되었을 때 자동으로 이 바인딩을 승인하고, 기본적으로 유효하지 않은 컨트롤 주위에 붉은 테두리를 보여줍니다. 이것은 다음 그림과 같습니다.
사용자 삽입 이미지

WPF는 사용자가 유효한 데이터를 입력할 때까지 유효하지 않은 컨트롤을 제한하지 않습니다. 이것은 사용자가 다이얼로그 박스에서 데이터가 유효하든 그렇지 않든 간에 자유롭게 컨트롤들을 이동할 수 있으므로 다이얼로그 박스를 위해 좋은 동작입니다. 그러나, 이것은 사용자가 유효하지 않은 데이터를 입력하고 OK 버튼을 누를 수 있다는 것을 의미합니다. 이런 이유로, 코드는 또한 유효하지 않은 데이터에 대한 보호를 위하여, 다이얼로그 박스가 승인되기 전에 모든 컨트롤을 유효화할 필요가 있습니다. 이것은 OK 버튼의 Click 이벤트 핸들러에서 할 수 있습니다.

C#
public partial class MarginsDialogBox : Window
{
    ...
    void okButton_Click(object sender, RoutedEventArgs e)
    {
        // 유효하지 않은 데이터가 있을 경우 다이얼로그 박스를 승인하지 말 것.
        if (!IsValid(this)) return;
        ...
    }
    ...
    // 윈도에 있는 모든 의존성있는 객체의 유효성 확인.
    bool IsValid(DependencyObject node)
    {
        // 객체가 있는지 확인.
        if (node != null)
        {
            // 객체가 유효한지 확인.
            // NOTE: Validation.GetHasError는 유효성 규칙이 붙은 컨트롤을 위해 동작합니다.
            bool isValid = !Validation.GetHasError(node);
            if (!isValid)
            {
                // 객체가 유효하지 않고, 포커스를 받을 수 있다면,
                // 포커스를 맞춤.
                if (node is IInputElement) Keyboard.Focus((IInputElement)node);
                return false;
            }
        }

        // 객체가 유효하다면, 모든 자식 객체를 확인.
        foreach (object subnode in LogicalTreeHelper.GetChildren(node))
        {
            if (subnode is DependencyObject)
            {  
                // 자식 객체가 유효하지 않다면 즉시 false를 반환하고,
                // 그렇지 않으면 검사를 계속함.
                if (IsValid((DependencyObject)subnode) == false) return false;
            }
        }

        // 모든 객체가 유효함.
        return true;
    }
}

이 코드는 윈도 상에서 의존성 있는 모든 객체들을 열거하며, GetHasError의 반환값이 하나라도 유효하지 않다면, 유효하지 않은 컨트롤에 포커스가 맞춰지고, IsValidfalse를 반환하며, 윈도는 유효하지 않다고 판단합니다.

일단 다이얼로그 박스가 유효화되면, 안전하게 닫고 반환할 수 있습니다. 이것은 다이얼로그 결과가 설정되었다는 것을 의미합니다.

모덜 다이얼로그 결과 설정하기
ShowDialog를 사용하여 다이얼로그 박스를 여는 것은 호출하는 코드에 있는 코드는 ShowDialog가 반환될 때까지 기다린다는 점에서 기본적으로 메소드 호출과 비슷합니다. ShowDialog가 반환되었을 때, 호출하는 코드는 사용자가 다이얼로그 박스에서 적용(apply)하여 수집한 데이터인지 아닌지 즉, 확인했는지 취소했는지를 결정할 필요가 있습니다. 사용자가 다이얼로그 박스를 확인했는지 취소했는지 보고하기 위해, 다이얼로그 박스는 반드시 다이얼로그 박스 결과값을 반환해야 합니다.

다이얼로그 박스가 확인되면, OK 버튼을 눌렀을 때 DialogResult 속성을 설정함으로써 획득되는 true의 다이얼로그 박스 결과를 반환해야 합니다.

XAML
<Window ... >
    ...
    <!-- Accept or Cancel -->
    <StackPanel Grid.Column="0" Grid.ColumnSpan="2" Grid.Row="4">
      <Button Name="okButton" Click="okButton_Click" IsDefault="True">OK</Button>
      ...
    </StackPanel>
  </Grid >
</Window>

C#
public partial class MarginsDialogBox : Window
{
    ...
    void okButton_Click(object sender, RoutedEventArgs e)
    {
        // Dialog box accepted
        this.DialogResult = true;
    }
    ...
}

DialogResult 속성을 설정하는 것은 또한 명시적으로 Close를 호출하지 않아도 윈도가 자동으로 닫히는 원인이 된다는 것을 유념하십시오.

취소된 다이얼로그 박스는 false의 다이얼로그 박스 결과를 가져야 합니다.

XAML
<Window ... >
    ...
    <!-- Accept or Cancel -->
    <StackPanel Grid.Column="0" Grid.ColumnSpan="2" Grid.Row="4">
      ...
      <Button Name="cancelButton" Click="cancelButton_Click" IsCancel="True">Cancel</Button>
    </StackPanel>
  </Grid >
</Window>

C#
public partial class MarginsDialogBox : Window
{
    ...
    void cancelButton_Click(object sender, RoutedEventArgs e)
    {
        // Dialog box canceled
        this.DialogResult = false;
    }
    ...
}

그러나 IsCancel 속성이 true로 설정되어 있는 버튼이 있고 사용자가 그 버튼이나 ESC키를 눌렀을 때는 DialogResult는 자동으로 false로 설정됩니다. 다음의 코드는 Click 이벤트 핸들러가 없이 전술한 코드와 같은 효과를 얻을 수 있습니다.

XAML
<Window ... >
    ...
    <!-- Accept or Cancel -->
    <StackPanel Grid.Column="0" Grid.ColumnSpan="2" Grid.Row="4">
      ...
      <Button Name="cancelButton" IsCancel="True">Cancel</Button>
    </StackPanel>
  </Grid >
</Window>

다이얼로그 박스는 사용자가 타이틀 바에 있는 Close 버튼을 누르거나 시스템 메뉴에서 Close 메뉴 아이템을 선택할 때 자동으로 true를 반환할 것입니다.

모덜 다이얼로그 박스에서 반환된 데이터 처리하기
DialogResult가 다이얼로그 박스에 의해 설정되면 호출하는 코드는 ShowDialog 메소드가 반환되었을 때 DialogResult 속성을 검사하여 다이얼로그 박스 결과를 얻을 수 있습니다.

C#
public partial class MainWindow : Window
{
    ...
    void formatMarginsMenuItem_Click(object sender, RoutedEventArgs e)
    {
        // Instantiate the dialog box
        MarginsDialogBox dlg = new MarginsDialogBox();

        // Configure the dialog box
        dlg.Owner = this;
        dlg.DocumentMargin = this.documentTextBox.Margin;

        // Open the dialog box modally
        dlg.ShowDialog();

        // Process data entered by user if dialog box is accepted
        if (dlg.DialogResult == true)
        {
            // Update fonts
            this.documentTextBox.Margin = dlg.DocumentMargin;
        }
    }
    ...
}

사용자가 다이얼로그 박스를 확인하면 호출하는 코드는 그것을 사용자에 의해 다이얼로그 박스로 입력된 값을 받고 처리하기 위한 큐로 사용합니다.

노트:
일단 ShowDialog가 반환되면 다이얼로그 박스는 다시 열 수 없고, 새 인스턴스를 대신 생성해야 합니다.

사용자가 다이얼로그 박스를 취소하면 호출하는 코드는 사용자가 제공한 데이터를 처리해선 안됩니다.

모덜리스 사용자 정의 다이얼로그 박스 생성하기
다음 그림의 FindDialogBox와 같은 모덜리스 다이얼로그 박스는 모덜 다이얼로그 박스와 같은 기본 형태를 가집니다.
사용자 삽입 이미지

그러나 동작은 다음 토픽에서 설명되는 것처럼 약간 다릅니다.

모덜리스 다이얼로그 박스 열기
모덜리스 다이얼로그 박스는 Show 메소드를 호출함으로써 열립니다.

C#
void editFindMenuItem_Click(object sender, RoutedEventArgs e)
{
    // Instantiate the dialog box
    FindDialogBox dlg = new FindDialogBox(this.documentTextBox.Text);

    // Open the dialog box modally
    dlg.Show();
}

다이얼로그 박스를 열기위해 ShowDialog를 사용하는 것과는 달리 Show는 즉시 반환됩니다. 따라서 호출한 윈도는 모덜리스 다이얼로그 박스가 닫혔을 때 전달할 수 없습니다. 그러므로 더 자세한 처리를 위해 다이얼로그 박스로부터 다이얼로그 박스 결과를 검사하거나 데이터를 얻을 수 있는 시점을 알 수 없습니다. 다이얼로그 박스는 처리를 위해 호출한 윈도에게 데이터를 반환할 대안을 만들 필요가 있습니다.

모덜리스 다이얼로그 박스에서 반환된 데이터 처리하기
이 예제에서 FindDialogBox는 어떤 정해진 빈도 없이 검색된 텍스트에 따라 하나 또는 그 이상의 검색 결과를 메인 윈도에 반환할 것입니다. 모덜 다이얼로그 박스의 경우처럼 모덜리스 다이얼로그 박스는 속성을 사용하여 결과를 반환할 수 있습니다. 그러나 다이얼로그 박스를 소유한 윈도는 언제 그 속성을 검사해야 하는지 알 필요가 있습니다. 다이얼로그 박스가 이것을 가능하게 하는 한가지 방법은 언제든 텍스트가 발견되었을 때 발생하는 이벤트를 구현하는 것입니다. FindDialogBox는 이런 목적으로 딜리게이트를 최우선으로 요구하는 TextFoundEvent를 구현합니다.

C#
public delegate void TextFoundEventHandler(object sender, EventArgs e);

TextFoundEventHandler 딜리게이트를 이용하여 FindDialogBox는 다음과 같이 TextFoundEvent를 구현합니다.

C#
public partial class FindDialogBox : Window
{
    ...
    public event TextFoundEventHandler TextFound;
    ...
    protected virtual void OnTextFound()
    {
        TextFoundEventHandler textFound = this.TextFound;
        if (textFound != null) textFound(this, EventArgs.Empty);
    }
}

따라서 찾기는 검색 결과가 나오면 이벤트를 띄웁니다.

C#
public partial class FindDialogBox : Window
{
    ...
    void findButton_Click(object sender, RoutedEventArgs e) {
        ...
        // Text found
        this.index = match.Index;
        this.length = match.Length;
        OnTextFound();
        ...
    }
    ...
}

소유 윈도는 이 이벤트를 등록하고 처리할 필요가 있습니다.

C#
public partial class MainWindow : Window
{
    ...
    void dlg_TextFound(object sender, EventArgs e)
    {
        // Get the find dialog box that raised the event
        FindDialogBox dlg = (FindDialogBox)sender;

        // Get find results and select found text
        this.documentTextBox.Select(dlg.Index, dlg.Length);
        this.documentTextBox.Focus();
    }
}

모덜리스 다이얼로그 박스 닫기
DialogResult가 설정될 필요가 없기 때문에 다음을 포함하는 시스템 제공 메커니즘을 사용하여 모덜리스 다이얼로그를 닫을 수 있습니다.
  • 타이틀 바의 Close 버튼을 클릭.
  • ALT+F4 누름.
  • System Menu | Close를 선택
또는 취소 버튼을 클릭하면 코드에서 Close를 호출할 수 있습니다.

C#
public partial class FindDialogBox : Window
{
    ...
    void cancelButton_Click(object sender, RoutedEventArgs e)
    {
        // Close dialog box
        this.Close();
    }
}


See Also

Concepts
Popup Overview

Other Resources
Dialog Box Sample
Wizard Sample
ColorPicker Custom Control Sample
Font Dialog Box Demo
신고
Posted by gongdo

MSDN : http://msdn2.microsoft.com/en-us/library/ms748948.aspx

WPF Windows Overview

사용자는 WPF 독립 애플리케이션과 주로 시각화한 데이터 컨텐트를 보여주고 사용자를 데이터와 상호작용 할 수 있도록 하는 윈도를 통하여 상호작용 합니다.

이 토픽은 다음 섹션을 담고 있습니다.

Window 클래스

다음 그림은 일반적인 윈도의 요소를 나타냅니다.

사용자 삽입 이미지

윈도는 비클라이언트 영역과 클라이언트 영역의 두 영영으로 나뉩니다.

윈도의 비클라이언트 영역은 WPF에 의해 구현되고, 대부분의 윈도에게 공통적인 다음과 같은 요소를 포함합니다.

  • 테두리(border)
  • 타이틀 바
  • 아이콘
  • 최소화, 최대화 및 원래 크기로 버튼
  • 닫기 버튼
  • 최소화, 최대화, 원래 크기로, 이동, 크기 조정 및 닫기를 위한 메뉴 아이템을 제공하는 시스템 메뉴

윈도의 클라이언트 영역은 윈도의 비클라이언트 영역 내의 영역이고, 윈도-정의(window-specific)내용을 표현하기 위해 개발자가 사용합니다.

WPF에서, 윈도는 다음과 같은 것을 가능케하는 Window 클래스에 의해 캡슐화됩니다.

  • 윈도의 크기, 위치 및 형태를 설정.
  • 윈도 내에 내용을 얹음.
  • 윈도를 보여줌.
  • 윈도의 라이프타임을 관리

메시지 박스와 다이얼로그 박스는 윈도의 다른 형식이며 Dialog Boxex Overview에서 다룹니다. 또한, NavigationWindowWindow에서 상속된 윈도의 특별한 형식이며 컨텐트를 표시하고 운항(네비게이션)하기 위한 지원을 확장합니다(Navigation Overview를 참고합니다).

윈도 구현

윈도의 구현은 형태(appearance)와 동작(behavior)을 포괄합니다. 형태는 윈도를 보여주는 방법이며, 동작은 윈도가 작용하는 방법입니다. WPF에서, 코드나 마크업 혹은 둘 다를 사용하여 윈도의 형태와 동작을 구현할 수 있습니다. 그러나, 마크업과 코드-비하인드가 -둘을 모두 사용하는 것이- 가장 일반적입니다.

마크업과 코드-비하인드에서 윈도를 정의하기
마크업과 코드-비하인드를 모두 사용하여 윈도를 구현하는 것은, 형태를 정의하기 위해 XAML의 풍부한 표현을 활용할 수 있고, 동작을 구현하기 위해 코드를 사용하는 것과 같이 둘 모두를 위해 가장 좋습니다.

다음 예제는 마크업과 코드를 모두 사용하여 구현된 윈도를 보여줍니다.
(※역주 : 원문에는 모두 XAML 코드로 나와있지만 내용상 XAML과 C#으로 구분하였습니다.)

XAML
<Window
    xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
    xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
    x:Class="MarkupAndCodeBehindWindow">
  <!-- Client Area (for content) -->
</Window>
C#

using System.Windows;

public partial class MarkupAndCodeBehindWindow : Window

{

    public MarkupAndCodeBehindWindow()

    {

        InitializeComponent();

    }

}

마크업 파일과 코드-비하인드 파일이 함께 동작하게 하기 위해서 다음과 같은 사항이 요구됩니다.

  • 마크업에서, Window 엘리먼트는 x:Class 어트리뷰트에 의해 지정된 이름을 가진 프로젝트가 빌드될 때 마크업 파일을 위한 partial class를 생성하도록 MSBuild에게 지시하는 x:Class 어트리뷰트를 포함해야 합니다. 이것은 XAML 스키마(xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml")를 위한 추가적인 XML 네임스페이스 선언을 필요로 합니다. 부분적으로 생성된 partial class는 이벤트를 등록하고 마크업에 의해 구현된 프로퍼티를 설정하기 위해 호출되는 InitializeComponent를 구현합니다.
  • 코드-비하인드에서, 클래스는 반드시 마크업의 x:Class 어트리뷰트에 의해 지정된 것과 같은 이름을 가진 partial class이어야 하고, Window를 상속할 필요가 있습니다. 이것은 코드-비하인드 파일이 빌드될 때 마크업 파일을 위해 생성된 partial class와 연결되도록 합니다(Building a WPF Application을 참고).
  • 코드-비하인드에서, 클래스는 반드시 InitializeComponent 메소드를 호출하는 생성자를 구현해야 하며 그렇지 않을 경우, 마크업은 적용되지 않을 것입니다.
노트:
Microsoft Visual Studio를 사용하여 프로젝트에 새 윈도를 추가할 때, 윈도는 마크업과 코드-비하인드를 모두 사용하여 구현되고, 마크업과 코드-비하인드 파일 사이의 연결을 생성하는데 필요한 설정을 포함합니다.

다음 예제는 어떻게 윈도 타이틀 설정, XAML을 사용한 버튼 선언 및 코드-비하인드에서 Click 이벤트를 처리하기 위해 마크업과 코드-비하인드를 사용하는지를 보여줍니다.
(※역주 : 역시 XAML과 C#으로 나눕니다.)

XAML
<Window
  xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
  xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
  x:Class="MarkupAndCodeBehindWindow"
  Title="WindowsOverviewSnippetsCSharp"
  Height="800"
  Width="600">
    <!-- Client Area (for content) -->
    <Button Click="button_Click">Window Content</Button>
</Window>
C#

using System.Windows;

public partial class MarkupAndCodeBehindWindow : Window

{

    public MarkupAndCodeBehindWindow()

    {

        InitializeComponent();

    }


    void button_Click(object sender, RoutedEventArgs e)

    {

        MessageBox.Show("Button was clicked.");

    }

}

MSBuild를 위한 윈도 정의 설정하기

윈도를 어떻게 정의하느냐에 따라 Microsoft build engine(MSBuild)를 위해 어떻게 설정되었는지를 결정합니다. 마크업과 코드-비하인드 모두를 사용하여 정의된 윈도의 경우,

  • 마크업 파일은 MSBuild Page 아이템으로 설정되어야 합니다.
  • 코드-비하인드 파일은 MSBuild Compie 아이템으로 설정해야 합니다.

이것은 다음 예제와 같이 표시할 수 있습니다.
(※역주 : 다음 코드는 Visual Studio의 프로젝트 파일(.csproj 또는 .vbproj)를 텍스트 편집기로 열여보면 확인할 수 있고, 물론 IDE를 사용하는 경우 이 코드를 직접 수정할 필요가 없습니다. 또한 원문에서의 Include 속성에 들어간 공백은 오타로 생각되어 제거 하였습니다.)

<Project
    DefaultTargets="Build"
    xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
    ...
    <Page Include="MarkupAndCodeBehindWindow.xaml" />
    <Compile Include="MarkupAndCodeBehindWindow.xaml.cs" />
    ...
</Project>

여기에서, 코드-비하인드 파일은 MSBuild Compile 아이템으로 설정되었습니다. 또한, 코드-비하인드 파일은 마크업 파일의 이름에 추가적인 언어 구분 접미어(.cs 또는 .vb)가 붙은 것과 같은 이름을 갖습니다. 이 접미어는 마이크로소프트 비주얼 스튜디오가 기본적으로 이런 규칙을 사용하긴 하지만 반드시 필요하진 않습니다.

노트:
WPF 애플리케이션 빌드하기의 더 자세한 내용은 Building a WPF Application을 참고합니다.

윈도 라이프타임

한 번 윈도가 MSBuild를 위해 정의되고 설정되면, 애플리케이션에서 그것을 보여줄 수 있습니다. 어떤 클래스에서도, 윈도는 최초로 인스턴스화 되었을 때 시작되어, 그것이 보이게 된 후 활성화되며 최종적으로 닫히기 전에 비활성화되는 라이프타임을 가집니다.

윈도 열기
윈도를 열기 위해, 다음 예제와 같이 먼저 그것의 인스턴스를 생성해야 합니다.

XAML
<Application
    xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
    xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
    x:Class="App"
    Startup="app_Startup">
</Application>
C#

using System.Windows;

public partial class App : Application

{

    void app_Startup(object sender, StartupEventArgs e)

    {

        // Create a window

        MarkupAndCodeBehindWindow window = new MarkupAndCodeBehindWindow();


        // Open a window

        window.Show();

    }

}

이 예제에서, MarkupAndCodeBehindWindow는 애플리케이션이 시작될 때 인스턴스화 됩니다(Application Management Overview를 참고).

윈도가 인스턴스화 될 때, 그것의 참조가 Application 객체에 의해 관리되는 윈도의 목록(System.Windows.Application.Windows 참고)에 자동적으로 추가됩니다. 또한, 첫 윈도가 인스턴스화 될 때, Application에 의해 기본값으로 메인 애플리케이션 윈도로 설정됩니다(System.Windows.Application 참고).

윈도는 Show 메소드를 호출함으로서 다음 그림이 보여주는 것 처럼 마침내 열립니다.

사용자 삽입 이미지

Show 호출에 의해 열린 윈도는 모덜리스 윈도이며, 이것은 애플리케이션이 사용자가 같은 애플리케이션 내의 다른 윈도를 활성화 할 수 있도록 허용하는 모드로 동작한다는 것을 의미합니다. Window는 또한 모덜 윈도로 열기위해 사용되는 ShowDialog 메소드를 구현합니다. 대부분의 모덜 윈도의 일반적 형식은 Dialog Boxes Overview에서 자세히 다루는 다이얼로그 박스입니다.

더 간단하게, 윈도 구현이 마크업을 포함하는 한, 마크업의 StartupUri 속성을 설정하여 메인 윈도를 자동적으로 열 수 있도록 애플리케이션 정의를 선언적으로 설정할 수 있습니다.

XAML
<Application
    xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
    xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
    x:Class="App"
    StartupUri="MarkupAndCodeBehindWindow.xaml">
</Application>

애플리케이션이 시작할 때, 이 마크업은 MarkupAndCodeBehindWindow 윈도가 Show 메소드 호출에 의해 모덜리스로 열리도록 합니다.

Show가 호출되었을 때, 윈도는 그것이 실제로 보이기 전에 처리할 어떤 초기화 작업이 필요합니다. 초기화의 초점은 사용자 입력을 받도록 할 기반의 구성에 맞춰져 있습니다. 초기화가 완료되었을 때, SourceInitialized 이벤트가 발생되고 윈도가 보이게 됩니다.

윈도 소유권
윈도가 Show 호출로 열렸을 때, 그것과 관계가 있는, 또는 그것을 생성한 윈도에 대한 어떠한 정보도 가지고 있지 않습니다. 사용자는 다른 것들과 독립적으로 각 윈도와 상호작용 할 수 있을 것입니다. 이것은 윈도가 다음과 같이 할 수 있다는 것을 의미합니다.

  • 다른 윈도를 가리기(true로 설정된 Topmost 속성을 가진 윈도가 없다면).
  • 다른 윈도에 영향을 주지 않고 최소화, 최대화 및 원래 크기로 돌아가기.

어떤 애플리케이션을 위해, 열려있는 윈도는 그것을 열었던 윈도와 밀접한 관계를 가질 필요가 있습니다. 예를 들어, 통합 개발 환경(IDE) 애플리케이션은 항상 다른 윈도를 생성하거나, 닫거나, 최소화 하거나, 최대화 하거나, 복구하기 위해서 그들의 위에 있어야 할 속성이나 툴 윈도와 같은 윈도를 열 것입니다.

Owner 속성을 설정하여 준비되는 한 윈도가 다른 윈도를 소유(own)하는 관계를 만들어 이러한 동작을 구현할 수 있습니다.

C#
using System.Windows;
public partial class OwnerWindow : System.Windows.Window
{
    public OwnerWindow()
    {
        InitializeComponent();
    }

    void OpenOwnedWindow()
    {
        // NOTE: 소유자는 다른 윈도를 소유하기 전에 반드시 보여야 합니다.
        // Create new owned window and show it
        OwnedWindow ownedWindow = new OwnedWindow();
        ownedWindow.Owner = this;
        ownedWindow.Show();
    }
}

한번 소유권이 만들어지면, 소유된 윈도는 Owner 속성을 통해 자신을 소유한 윈도를 참조할 수 있습니다. 소유 윈도는 OwnedWindows 속성을 나열하여 그것이 소유하고 있는 모든 윈도를 알 수 있습니다.

윈도 활성화
윈도가 처음으로 열렸을 때, 키 눌림과 마우스 클릭과 같은 현재 사용자의 입력을 포착하는 것을 의미하는 포그라운드 윈도(foreground window)가 되며, 이 윈도는 활성 윈도(active window)라고도 합니다. 윈도는 처음으로 열렸거나, 사용자가 선택하였을 때 활성 윈도가 됩니다. 이 모든 경우, 윈도는 Activated 이벤트를 띄웁니다.

노트:
윈도가 처음으로 열렸을 때, Activated 이벤트가 발생된 후 LoadedContentRendered 이벤트가 발생합니다. 따라서, 윈도는 ContentRendered가 발생하였을 때만 열려야 할지를 고려해야 합니다.

윈도가 활성화 된 후, 사용자는 같은 애플리케이션 내의 또 다른 윈도를 활성화 하거나 다른 애플리케이션을 활성화 할 수 있습니다. 그랬을 때, 현재 활성 윈도는 비활성화 되고 Deactivated 이벤트를 띄웁니다.

ActivatedDeactivated를 처리하는 한 가지 이유는 예를 들어, 게임이나 비디오 플레이어와 같이 끊임 없는 사용자의 입력이나 집중이 필요한 윈도가 활성화 되었을 때에만 동작할 수 있는 기능을 사용 가능 또는 사용 불가능하게 하기 위해서 입니다.

다음 예제는 이 동작을 구현하기 위해 어떻게 ActivatedDeactivated를 처리하는지 보여줍니다.

XAML
<Window
    x:Class="CustomMediaPlayerWindow"
    xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
    xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
    Title="Custom Media Player"
    Activated="window_Activated"
    Deactivated="window_Deactivated">
  ...
</Window>
C#

using System.Windows;

public partial class CustomMediaPlayerWindow : Window

{

    ...

    bool isMediaElementPlaying;

    void window_Activated(object sender, EventArgs e)

    {

        // 윈도가 활성화 되면 미디어 재생을 재개

        If (this.isMediaElementPlaying) this.mediaElement.Play();

    }

    void window_Deactivated(object sender, EventArgs e)

    {

        // 미디어가 재생 중이고 윈도가 비활성화 되면 재생을 일시 중지

        if (this.isMediaElementPlaying) this.mediaElement.Pause();

    }

}

노트:
완전한 샘플은 Window Activation and Deactivation Sample을 참고합니다.

때로, 윈도는 활성 윈도가 아닐지라도 코드를 계속 실행해야 할지도 모릅니다. 예를 들어, 메일 클라이언트는 사용자가 다른 애플리케이션을 사용하는 동안 메일 서버를 지속적으로 폴링할 것입니다. 이와 같은 애플리케이션은 종종 메인 윈도가 비활성화 되었을 때 다른, 혹은 추가적인 동작을 제공합니다. 메일 프로그램의 경우를 고려해봤을 때, 이것은 새 메일을 받은 편지함에 추가하는 것 뿐만 아니라, 사용자에게 통지하기 위한 시스템 트레이에 아이콘을 추가하는 것도 의미합니다. 애플리케이션이 이런 동작을 수행할 필요가 있는지를 결정하기 위해, IsActive 속성을 검사하여 윈도가 활성화 되었는지 아닌지를 검출할 수 있습니다.

다른 경우, 윈도는 특별히 더 긴급하게 사용자에게 통지를 할 필요가 있다면, 활성 윈도가 되길 원할 것입니다. 이것은 Activate 메소드를 호출하여 가능합니다.

노트 :
System.Windows.Application.ActivatedSystem.Windows.Application.Deactivated 이벤트를 사용하여 애플리케이션-스코프 활성화를 처리할 수 있습니다.

윈도 닫기
사용자가 윈도 사용을 마쳤을 때, 그것을 닫길 바랄 것입니다. 윈도는 다음과 같은 비클라이언트 영역의 요소를 사용하여 닫을 수 있습니다.

  • System 메뉴의 Close 아이템.
  • ALT+F4를 누름.
  • Close 버튼을 누름.

개발자는 윈도를 닫기 위해 다음과 같이 클라이언트 영역에 커스텀 메커니즘을 추가할 수도 있습니다.

  • 일반적으로 메인 애플리케이션을 위한 File 메뉴에 있는 Exit 아이템.
  • 일반적으로 보조 애플리케이션 윈도 상의 File 메뉴에 있는 Close 아이템.
  • 일반적으로 모덜 다이얼로그 박스에 있는 Cancel 버튼.
  • 일반적으로 모덜리스 다이얼로그 박스에 있는 Close 버튼.

위의 개발자 제공의 메커니즘 중 하나에 응답하여 윈도를 닫기 위해, Close 메소드를 호출할 필요가 있습니다.

다음 예제는 File | Exit 메뉴가 클릭되었을 때 어떻게 윈도를 닫는지를 보여줍니다.

XAML
<Window
    x:Class="CustomMediaPlayerWindow"
    xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
    xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
    Title="Custom Media Player"
    Activated="window_Activated"
    Deactivated="window_Deactivated">
  ...
  <MenuItem Header="_File">
      <MenuItem Header="_Exit" Click="exitMenu_Click" />
  </MenuItem>
  ...
</Window>
C#

using System.Windows;

public partial class CustomMediaPlayerWindow : Window

{

    ...

    void exitMenu_Click(object sender, EventArgs e)

    {

        // Close the window

        this.Close();

    }

}

윈도가 닫힐 때, 윈도는 ClosingClosed 이벤트를 띄우게 됩니다.

Closing은 윈도가 닫히기 전에 발생하고, 윈도가 실제로 닫히는 것을 막을 수 있게 합니다. 이렇게 하는 일반적인 이유로는 윈도가 저장되어야 할 데이터를 포함하고 있거나 어떤 활동이 일어나는 경우가 있습니다. 이 상황에서, 윈도는 Closing 이벤트를 사용하여 사용자에게 통지하고 계속해서 윈도를 닫을지 말지 물을 수 있습니다. 본질적으로, 이것은 저장되지 않은 데이터를 포함한 윈도를 닫도록 시도할지 모르는 사용자를 위한 백업 테크닉입니다.

다음과 같이 Closing 처리를 할 수 있습니다.

XAML
<Window
    x:Class="CustomMediaPlayerWindow"
    xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
    xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
    Title="Custom Media Player"
    Activated="window_Activated"
    Deactivated="window_Deactivated"
    Closing="window_Closing">
  ...
</Window>
C#

using System.Windows;

public partial class CustomMediaPlayerWindow : Window

{

    ...

    void window_Closing(object sender, CancelEventArgs e)

    {

        // Ask user if they want to close the window

        if (this.isMediaElementPlaying)

        {

            string msg = "Media is playing. Really close?";

            string title = "Custom Media Player?";

            MessageBoxButton buttons = MessageBoxButton.YesNo;

            MessageBoxImage icon = MessageBoxImage.Warning;


            // Show message box and get user's answer

            MessageBoxResult result =

                MessageBox.Show(msg, title, buttons, icon);


            // Don't close window if user clicked No

            e.Cancel = (result == MessageBoxResult.No);

        }

    }

}

Closing 이벤트 핸들러는 true로 설정하여 윈도 닫기를 막기 위한 Boolean Cancel 속성을 노출하는 CancelEventArgs에 의해 전달됩니다.

Closing이 처리되지 않거나 처리되었지만 취소되지 않았다면, 윈도는 닫힙니다. 윈도를 닫기 직전에, 그리고 Closing이 처리된 후, Closed가 발생됩니다.

노트:
애플리케이션은 메인 윈도가 닫히거나(MainWindow 참고) 마지막 윈도가 닫힐 때 자동적으로 종료될 수 있도록 설정할 수 있습니다. ShutdownMode를 참고합니다.

윈도는 비클라이언트 영역과 클라이언트 영영이 제공하는 메커니즘을 통해 명시적으로 종료될 수 있으며, 또한 다음과 같이 애플리케이션이나 윈도의 다른 부분에 의한 동작의 결과에 의해 묵시적으로 닫힐 수도 있습니다.

  • 사용자가 로그 오프하거나 윈도를 종료하는 경우.
  • 윈도의 소유자가 닫히는 경우(Owner 참고).
  • 메인 애플리케이션 윈도가 닫히고 ShutdownMode가 OnMainWindowClose인 경우.
  • Shutdown이 호출된 경우.
노트:
윈도는 닫힌 이후에 다시 열 수 없습니다.

윈도 라이프타임 이벤트
다음 그림은 윈도의 라이프타임내의 핵심 이벤트와 그것이 발생하는 순서를 나타냅니다.

사용자 삽입 이미지

윈도 위치

윈도가 열리면, LeftTop 속성으로부터 확정될 수 있는 데스크탑(바탕 화면)에 대한 xy 경로를 가집니다. 윈도의 현재 위치를 변경하고 싶다면 이 속성을 설정할 수 있습니다. Window는 또한 처음으로 열려 나타날 때의 위치를 설정할 수 있습니다.

시작 위치
윈도가 열릴 때 윈도가 나타날 위치는 WindowStartupLocation 속성에 의해 결정되며, 다음의 WindowStartupLocation 열거 값중 하나로 설정할 수 있습니다.

시작 위치가 Manual로 지정되면, 윈도는 Windows(운영체제)에 나타날 위치를 물을 것입니다. LeftTop 속성을 사용하여 위치를 지정하는 것으로 이것을 오버라이드 할 수 있습니다.

최상위 윈도와 Z-Order
윈도는 각각 LeftTop 속성으로 지정되는 xy위치를 가지고 있습니다. 추가적으로, 윈도는 다른 윈도에 대한 수직 위치를 결정하는 z 축에 대한 위치를 가집니다. 이것은 z-order로 알려져 있고, 일반(normal) z-order최상위(topmost) z-order의 두 형식을 가집니다. 일반 z-order에 있는 윈도는 언제나 최상위 z-order에 있는 윈도보다 아래에 위치합니다. 최상위 z-order에 위치하기 위해서, 윈도는 반드시 Topmost 속성을 true로 설정해야 합니다.

XAML
<Window ... Topmost="True">
  ...
</Window>

각 z-order에서, 현재 활성 윈도가 같은 z-order에 있는 다른 모든 윈도보다 위에 나타납니다.

다음 그림은 일반과 최상위 z-order에 있는 윈도상에서 Topmost 속성의 효과를 나타냅니다.

사용자 삽입 이미지

윈도 크기

데스크탑에서의 위치를 가지는 것 외에, 윈도는 그것이 보이는 크기를 가집니다. 윈도 크기는 각종 너비와 높이 속성 및 SizeToContent와 같은 몇몇 Window 속성에 의해 결정됩니다.

MinWidth, WidthMaxWidth는 윈도가 그 라이프타임동안 가질 수 있는 너비의 범위를 관리하고, 다음과 같이 설정할 수 있습니다.

XAML
<Window ... MinWidth="300" Width="400" MaxWidth="500">
  ...
</Window>

다음 그림은 어떻게 이 속성들이 윈도의 너비 범위에 적용되는지를 나타냅니다.

사용자 삽입 이미지

윈도 높이는 MinHeight, HeightMaxHeight에 의해 관리되고, 다음과 같이 설정할 수 있습니다.

XAML
<Window ... MinHeight="300" Height="400" MaxHeight="500">
  ...
</Window>

다음 그림은 어떻게 이 속성들이 윈도의 높이 범위에 적용되는지를 나타냅니다.

사용자 삽입 이미지

이러한 너비값과 높이값은 각각 범위를 지정하기 때문에, 크기 변경 가능한 윈도의 너비와 높이는 각 축을 위한 지정된 범위내에서만 지정하는 것이 가능합니다. 현재 너비와 높이는 각각 ActualWidthActualHeight를 조사하여 알 수 있습니다.

윈도의 너비와 높이가 윈도 내용의 크기에 맞출 필요가 있다면, SizeToContent 속성을 사용하여 다음과 같은 값으로 설정할 수 있습니다.

  • Manual. 효과 없음(기본값).
  • Width. 내용의 너비에 맞춤 : MinWidthMaxWidth를 내용의 너비로 설정하는 것과 같은 효과.
  • Height. 내용의 높이에 맞춤 : MinHeightMaxHeight을 내용의 높이로 설정하는 것과 같은 효과.
  • WidthAndHeight. 내용의 너비와 높이에 맞춤 : MinWidth, MaxWidthMinHeight, MaxHeight를 각각 내용의 너비 및 높이로 설정하는 것과 같은 효과.

다음 코드는 윈도가 처음 나타날 때 자동으로 내용의 수직과 수평에 맞춘 크기가 되는 윈도를 보여줍니다.

XAML
<Window ... SizeToContent="WidthAndHeight">
  ...
</Window>

크기 조절 속성의 우선 순위

본래, 윈도의 각 사이즈 속성은 크기 조절 가능한 윈도를 위한 너비와 높이의 범위를 정의하여 조합됩니다. 올바른 범위가 유지될 수 있도록, 윈도는 다음 우선 순위를 사용하여 크기 속성들의 값을 평가합니다.

  • 높이 속성들:
    System.Windows.FrameworkElement.MinHeight >
    System.Windows.FrameworkElement.MaxHeight >
    System.Windows.SizeToContent.Height / System.Windows.SizeToContent.WidthAndHeight >
    System.Windows.FrameworkElement.MaxHeight
  • 너비 속성들:
    System.Windows.FrameworkElement.MinWidth >
    System.Windows.FrameworkElement.MaxWidth >
    System.Windows.SizeToContent.Width / System.Windows.SizeToContent.WidthAndHeight >
    System.Windows.FrameworkElement.MaxWidth

Window Sizing Order of Precedence Sample을 사용하여 우선 순위를 실험해 볼 수 있습니다.

우선 순위는 또한 WindowState 속성으로 관리되는 윈도의 크기가 최대화 되었을 때의 크기도 결정합니다.

윈도 상태

크기 조절 가능한 윈도의 라이프타임동안, 윈도는 보통(normal), 최소화(minimized) 및 최대화(maximized) 상태를 가질 수 있습니다. 보통(normal) 상태의 윈도는 윈도의 기본 상태입니다. 이 상태를 가진 윈도는 현재 보이거나 테두리가 있고 크기 조절이 가능하다면, 사용자가 크기 조절 그립을 사용하여 이동하고 크기를 조절할 수 있게 합니다.

최소화(minimized) 상태의 윈도는 ShowInTaskbartrue로 설정이 되어 있을 경우, 태스크바의 버튼으로 축소합니다. 그렇지 않을 경우, 윈도는 가능한 가장 작은 크기로 축소하고, 자신의 위치를 데스크탑의 좌측 하단 구석으로 변경합니다. 어떤 최소화된 윈도의 종류도 테두리나 크기 조절 그립을 사용하여 크기를 조절하거나, 태스크 바에 있는 최소화된 윈도를 드래그하여 데스크탑으로 돌린다거나 할 수 없습니다. 다음 그림은 최소화된 윈도의 두 종류를 보여줍니다. (※역주 : MSDN! 그림을 빼먹다니! 이 부분은 다들 무슨 얘긴지 아시리라 믿습니다.)

최대화(maximized) 상태의 윈도는 MaxWidth, MaxHeightSizeToContent 속성에서 가능한 최대의 크기로 확장합니다. 최소화된 윈도처럼, 최대화된 윈도도 크기를 변경하거나 드래그할 수 없습니다.

윈도의 상태는 WindowState 속성을 세팅하여 설정할 수 있고, 다음 WindowState 열거 값중 하나의 값을 가집니다.

다음 예제는 어떻게 윈도가 열렸을 때 최대화되어 보이는 윈도를 생성하는지 보여줍니다.

XAML
<Window ... WindowState="Maximized">
  ...
</Window>

일반적으로, 윈도의 초기 상태를 설정하기 위해 WindowState를 설정할 것입니다. 일단 크기 변경 가능한 윈도가 보이면, 사용자는 윈도 상태를 변경하기 위하여 윈도의 타이틀 바에 있는 최소화, 최대화 및 이전 크기로 버튼을 사용할 수 있습니다.

윈도 형태

윈도-지정 내용에 버튼, 라벨 및 텍스트 박스 같은 것을 추가하여 윈도의 클라이언트 영역의 형태를 변경할 수 있습니다. 비클라이언트 영역을 설정하기 위해, Window는 윈도의 아이콘을 설정하기 위한 Icon과 제목을 설정하기 위한 Title과 같은 몇 가지 속성을 제공합니다.

또한 윈도의 resize mode, window style 및 데스크탑의 태스크바에 버튼을 보여줄지 여부를 설정하여 비클라이언트 영역의 형태나 동작을 변경할 수 있습니다.

Resize Mode
WindowStyle에 따라서, 사용자가 윈도의 크기를 변경하거나 다른 모든 것들을 할 수 있는지를 변경할 수 있습니다. 사이즈 조절과 관련하여, 윈도 스타일의 선택은 사용자가 윈도의 테두리를 마우스로 드래그하여 크기를 변경할 수 있을지, Minimize, MaximizeResize 버튼이 비클라이언트 영역에 나타날지, 사용가능한지에 영향을 미칩니다.

ResizeMode 속성을 설정하여 윈도 크기 조절이 어떻게 될지를 설정할 수 있고, 다음 ResizeMode 열거 값중 하나를 가집니다.

다음 그림은 각각의 효과를 나타냅니다.

사용자 삽입 이미지

WindowStyle과 같이, 윈도의 resize mode는 그 라이프타임 동안 변경되지는 않을 것이고, 대부분 마크업에서 그것을 설정할 것이라는 것을 의미합니다.

XAML
<Window ... ResizeMode="CanResizeWithGrip">
    ...
</Window>

윈도가 최대화, 최소화 또는 이전 크기로 되었는지는 WindowState 속성을 조사하여 알 수 있습니다.

Window Style
윈도의 비클라이언트 영역에서 노출되는 테두리는 대부분의 애플리케이션에 적당합니다. 그러나, 윈의 종류에 따라서는, 다른 형태의 테두리가 필요하거나, 전혀 필요하지 않은 상황이 있습니다.

윈도가 가질 테두리의 종류를 컨트롤하기 위해, WindowStyle 속성을 다음과 같은 WindowStyle 열거 값중 하나로 설정할 수 있습니다.

이 윈도 스타일의 효과는 다음 그림에 나타나 있습니다.

사용자 삽입 이미지

WindowStyle은 마크업이나 코드를 사용하여 설정할 수 있지만, 윈도의 라이프타임 동안 그것을 변경할 것 같지는 않으므로 대부분 마크업을 사용하여 설정할 것입니다.

XAML
<Window ... WindowStyle="ToolWindow">
    ...
</Window>

비사각형 윈도 스타일
또한 WindowStyle이 허용하는 테두리 스타일이 충분하지 않은 상황이 있습니다. 예를 들어, Microsoft Windows Media Player가 사용하는 것 처럼, 비사각형 테두리를 가진 애플리케이션을 만들고 싶은 경우가 있습니다.

예를 들어, 다음 그림과 같은 풍선 윈도를 생각해볼 수 있습니다.

사용자 삽입 이미지

이런 종류의 윈도는 WindowStyle 어트리뷰트를 None으로 설정하고, Window가 투명함을 가질 수 있는 특별한 지원을 사용하여 만들 수 있습니다.

XAML
<Window ...
  WindowStyle="None"
  AllowsTransparency="True"
  Background="Transparent">
    ...
</Window>

이것은 WindowStyle, AllowsTransparencyBackground 어트리뷰트의 조합이고 이 값들은 윈도를 완전히 투명하게 그리도록 합니다. 이것은 Path를 사용하여 원하는 테두리를 제공하여 가능합니다. 예를 들면,

XAML
<Window ...
  WindowStyle="None"
  AllowsTransparency="True"
  Background="Transparent">
    ...
    <!-- Path and fill for speech bubble UI -->
    <Path Stroke="DarkGray" StrokeThickness="2">
        ...
    </Path>
    ...
</Window>

윈도를 비사각형 테두리로 생성하였다면, WPF가 제공하는 비클라이언트 영역 요소를 사용할 수 없다는 것을 의미하며, 따라서, 반드시 스스로 구현해야 합니다.

Non-Rectangular Windows Sample을 참고합니다.

태스크바 표시
윈도의 기본 형태는 다음 그림과 같이 태스크바 버튼을 포함합니다.

사용자 삽입 이미지

어떤 윈도는 메시지 박스와 다이얼로그 박스(Dialog Boxes Overview를 참고)와 같이 태스크바 버튼을 가지지 않습니다. 윈도를 위한 태스크바 버튼이 보일지 말지를 ShowInTaskbar 속성(기본값으로 true)을 설정하여 변경할 수 있습니다.

XAML
<Window ... ShowInTaskbar="False">
    ...
</Window>


보안 고려 사항

Window는 인스턴트화 되기 위해 UnmanagedCode 보안 허가를 요구합니다. 로컬 머신에 설치되고 실행되는 애플리케이션을 위해, 이것은 애플리케이션에 부여되는 허가의 세트에 포함됩니다.

그러나, ClickOnce를 사용하여 Internet이나 LocalIntranet에서 시작된 애플리케이션에 부여된 허가의 세트에는 포함되지 않습니다. 따라서, 사용자는 ClickOnce 보안 경고를 받을 것이며, 애플리케이션이 완전히 신뢰되기 위한 허가 세트를 높힐 필요가 있을 것입니다.

추가적으로, XBAPs는 기본적으로 윈도나 다이얼로그 박스를 보일 수 없습니다. 독립 애플리케이션 보안에서의 고려사항을 다루는 WPF Security Strategy - Platform Security를 참고합니다.

See Also

Reference
Window
MeesageBox
NavigationWindow
Application
Concepts
Dialog Boxes Overview
Building a WPF Application

신고
Posted by gongdo

MSDN : http://msdn2.microsoft.com/en-us/library/aa970069.aspx

Pack URIs in WPF

애플리케이션 데이터 파일(WPF Application Data Files 참고)을 식별하기 위해, WPF는 잘 알려지고 확장성있는 uniform resource identifier(URI) 기반의 Pack URI Scheme 메커니즘을 제공합니다. Pack URI Scheme의 확장성은 WPF가 다양한 장소에 존재할 수 있는 몇 가지 애플리케이션 데이터 파일의 종류를 식별하기 위한 일관성있는 수단을 지원할 수 있게 합니다.

이 토픽은 다음과 같은 섹션을 담고 있습니다.

Pack URI 스키마

Open Packaging Conventions(OPC) 명세는 컨텐트를 조직하고 식별하기 위한 모델을 설명합니다. 이 모델의 핵심은 두 논리적인 패키지와 파츠(parts) 요소를 중심으로 합니다. pacakge는 다음 그림에서 표현된 하나 혹은 그 이상의 컨텐트 parts를 위한 컨테이너입니다.

사용자 삽입 이미지

이 파츠를 식별하기 위해, OPC는 RFC 2396의 확장성을 이용하여 Pack URI 스키마를 정의합니다. URI에 의해 지정되는 스키마는 http, ftpfile과 같이 잘 알려진 접두어에 의해 정의됩니다. Pack URI 스키마는 pack을 스키마로 사용하고 권한(autority)과 경로(path) 두 컴포넌트를 포함합니다. autority는 파트가 포함된 패키지의 종류를 지정하고, path는 패키지내의 파트의 위치를 지정합니다. 이 컨셉은 다음 그림으로 표현됩니다.

사용자 삽입 이미지

Pack URI 스키마에 따르는 URI는 "pack URI"이라고 하며, 다음과 같은 포맷을 가집니다.

pack://<authority><path>

패키지와 파츠의 컨셉은 애플리케이션(package)이 하나 또는 그 이상의 다음과 같은 애플리케이션 데이터 파일(parts)을 포함할 수 있다는 점에서 애플리케이션과 애플리케이션 데이터 파일과 비슷합니다.

  • 로컬 어셈블리에 컴파일된 리소스 파일
  • 참조된 어셈블리에 컴파일된 리소스 파일
  • 참조한 어셈블리에 컴파일된 리소스 파일
  • 컨텐트 파일
  • Site of origin 파일

이 애플리케이션의 네가지 종류에 접근하기 위해서, WPF는 application:/// 과 siteoforigin:///의 두 권한을 지원합니다. application:///권한은 컴파일 시점에 알려진 리소스 파일과 컨텐트 파일을 포함하는 애플리케이션 데이터 파일 식별에 사용됩니다. siteoforigin:/// 권한은 site of origin 파일의 식별에 사용됩니다.

노트:
Pack URI의 권한 컴포넌트는 패키지를 가르키는 임베디드 URI이고 반드시 RFC 2396을 준수해야 합니다. 추가적으로, "/" 문자는 반드시 ","로 대치되어야 하고, "%"와 "?" 같은 예약된 문자는 이스케이프될 필요가 있습니다. 상세한 것은 OPC를 참고합니다.

각 권한의 스코프는 다음 그림에 나타나 있습니다.

사용자 삽입 이미지

다음 토픽들은 리소스 파일, 컨텐트 파일 및 site of origin 파일을 구분하기 위한 경로와 함께, 이 두 권한을 사용한 Pack URI를 어떻게 생성하는지 설명합니다.

리소스 파일 Pack URI - 로컬 어셈블리

로컬 어셈블리에 컴파일된 리소스 파일을 위한 Pack URI는 다음의 권한과 경로를 사용합니다.

  • 권한(Authority): application:///
  • 경로(Path): 로컬 어셈블리 프로젝트 폴더의 루트에 대한 경로를 포함한 리소스 파일의 이름.

다음 예제는 로컬 어셈블리 프로젝트 폴더의 루트에 위치한 XAML 리소스 파일의 pack URI를 보여줍니다.

pack://application:,,,/ResourceFile.xaml

다음 예제는 로컬 어셈블리 프로젝트 폴더의 서브 폴더에 위치한 XAML 리소스 파일의 pack URI를 보여줍니다.

pack://application:,,,/Subfolder/ResourceFile.xaml

리소스 파일 Pack URI - 참조된 어셈블리

참조된 어셈블리에 컴파일된 리소스 파일을 위한 Pack URI는 다음의 권한과 경로를 사용합니다.

  • 권한(Authority): application:///
  • 경로(Path): 참조된 어셈블리에 컴파일된 리소스파일의 경로는 다음과 같은 포맷을 따릅니다.
    AssemblyShortName[;Version][;PublicKey];component/Path
    - AssemblyShortName은 참조된 어셈블리의 짧은 이름입니다.
    - ;Version [옵셔널]은 리소스파일을 담고 있는 참조된 어셈블리의 버전을 가리킵니다. 이것은 두개 혹은 그 이상의 참조된 어셈블리가 같은 짧은 이름을 가지고 로드되었을 때 사용됩니다.
    - ;PublicKey [옵셔널]은 참조된 어셈블리의 사인으로 사용된 공용 키를 가리킵니다. 이것은 두개 혹은 그 이상의 참조된 어셈블리가 같은 짧은 이름을 가지고 로드되었을 때 사용됩니다.
    - ;component는 어셈블리가 로컬 어셈블리로부터 참조되어 있음을 지정합니다.
    - /Path는 참조된 어셈블리 프로젝트 폴더의 루트에 대한 경로를 포함한 리소스 파일의 이름입니다.

다음 예제는 참조된 어셈블리 프로젝트 폴더의 루트에 위치한 XAML 리소스 파일의 pack URI를 보여줍니다.

pack://application:,,,/ReferencedAssembly;component/ResourceFile.xaml

다음 예제는 참조된 어셈블리 프로젝트 폴더의 서브 폴더에 위치한 XAML 리소스 파일의 pack URI를 보여줍니다.

pack://application:,,,/ReferencedAssembly;component/Subfolder/ResourceFile.xaml

다음 예제는 참조된 버전을 지정하는 어셈블리 프로젝트 폴더의 루트에 위치한 XAML 리소스 파일의 pack URI를 보여줍니다.

pack://application:,,,/ReferencedAssembly;v1.0.0.1;component/ResourceFile.xaml

컨텐트 파일 Pack URI

컨텐트 파일의 Pack URI는 다음과 같은 권한과 경로를 사용합니다.

  • 권한(Authority): application:///
  • 경로(Path): 애플리케이션의 메인 실행 어셈블리의 파일 시스템 위치에 대한 경로를 포함하는 컨텐트 파일의 이름입니다.

다음 예제는 실행 어셈블리와 같은 폴더에 위치한 XAML 컨텐트 파일의 Pack URI를 보여줍니다.

pack://application:,,,/ContentFile.xaml

다음 예제는 애플리케이션의 메인 실행 어셈블리의 파일 시스템 위치의 서브 폴더에 위치한 XAML 컨텐트 파일의 Pack URI를 보여줍니다.

pack://application:,,,/Subfolder/ContentFile.xaml

Site of Origin 파일 Pack URI

site of origin 파일의 Pack URI는 다음과 같은 권한과 경로를 사용합니다.

  • 권한(Authority): siteoforigin:///
  • 경로(Path): 실행 어셈블리가 실행된 위치에 대한 경로를 포함한 site of origin 파일의 이름입니다.

다음 예제는 실행 어셈블리가 실행된 위치에 저장된 XAML site of origin 파일의 Pack URI를 보여줍니다.

pack://siteoforigin:,,,/SiteOfOriginFile.xaml

다음 예제는 실행 어셈블리가 실행된 위치의 서브 폴더에 저장된 XAML site of origin 파일의 Pack URI를 보여줍니다.

pack://siteoforigin:,,,/Subfolder/SiteOfOriginFile.xaml

절대 vs 상대 Pack URI

전체 경로(fully-qualified) Pack URI는 스키마, 권한 및 경로를 포함하고 절대 Pack URI라고 생각할 수 있습니다. 개발자의 편의를 위해, XAML 엘리먼트는 일반적으로 경로만을 포함하는 상대 Pack URI를 가진 어트리뷰트를 적절하게 설정할 수 있게 합니다.

예를 들어, 다음과 같이 로컬 어셈블리에 있는 리소스 파일의 절대 Pack URI를 생각할 수 있습니다.

pack://application,,,/ResourceFile.xaml

이 리소스 파일을 가리키는 상대 Pack URI는 다음과 같습니다.

/ResourceFile.xaml

노트:
site of origin 파일은 어셈블리와 연관성이 없기 때문에, (절대) Pack URI만을 사용하여 가리킬 수 있습니다.

기본적으로, 상대 Pack URI 참조는 참조를 포함하는 마크업 파일이나 코드 파일에 대한 상대 경로로 생각할 수 있습니다. 그러나 제일 앞에 백슬래쉬가 사용된 경우, 상대 Pack URI 참조는 애플리케이션의 루트에 대한 상대 경로로 생각됩니다. 예를 들어, 다음 프로젝트 구조를 생각할 수 있습니다.

[Root]
App.xaml
Page2.xaml
    \[SubPages]
       Page1.xaml
       Page2.xaml

(SubPages에 있는)Page1.xaml이 SubPages에 있는 Page2.xaml 파일의 상대 Pack URI를 만들고 싶다면 다음과 같이 사용할 수 있습니다.

Page2.xaml

그러나, (SubPages에 있는)Page1.xaml이 루트 폴더에 있는 Page2.xaml 파일의 상대 Pack URI를 만들고 싶다면 다음과 같이 사용할 수 있습니다.

Page1.xaml (※역주 : 이 부분은 Page2.xaml이 되어야 맞다고 생각하는데... 좀 당황스럽고 자신이 없네요;)

Pack URI 분석

Pack URI 형식은 Pack URI가 로컬 리소스 파일 및 컨텐트 파일과 동일하게 보이도록 합니다.

pack://application:,,,/ResourceOrContentFile.xaml

이는 다음 상대 URI와 동일합니다.

/ResourceOrContentFile.xaml

이런 유사성 때문에, WPF는 Pack URI가 리소스 파일을 가리키는지 컨텐트 파일을 가리키는지를 결정하기 위한 방법을 필요로 합니다. Pack URI가 정보의 이 유형을 포함하지 않기 때문에, WPF는 다음과 같은 발견적(heuristic)인 방법을 사용하여 URI를 결정합니다.

  1. Pack URI와 일치하는 AssemblyAssociatedContentFileAttribute의 어셈블리 메타 데이터를 조사합니다.
  2. AssemblyAssociatedContentFileAttribute 어트리뷰트가 발견되면, Pack URI는 컨텐트 파일의 경로를 가리킵니다.
  3. AssemblyAssociatedContentFileAttribute 어트리뷰트가 발견되지 않으면, 열거된 로컬 어셈블리에 컴파일된 리소스 파일의 세트를 조사합니다.
  4. Pack URI의 경로와 일치하는 리소스 파일이 발견되면, Pack URI의 경로는 리소스 파일을 가리킵니다.
  5. 리소스가 발견되지 않으면, 내부적으로 무효화된(invalid) Uri를 생성합니다.
노트:
절대와 상대 Pack URI만이 리소스 분석에 포함됩니다. 참조된 어셈블리의 컨텐트 파일은 WPF에 의해 지원되지 않기 때문에 포함되지 않습니다. 참조된 어셈블리에 있는 임베디드 파일의 Pack URI는 참조된 어셈블리와 ;component 접미사에 의해 포함되기 때문에 고유합니다. site of origin 파일의 Pack URI는 siteoforigin:/// 권한만을 사용하기 때문에 고유합니다.

WPF 리소스 분석은 애플리케이션 데이터 파일의 위치에 독립적인 Pack URI를 생성할 수 있게 합니다. 따라서, Resource에서 Content로 비실행 데이터 파일의 빌드 형식을 바꿔도, Pack URI를 변경하지 않아도 됩니다.

Pack URI로 프로그램하기

다음과 같이 많은 WPF 클래스가 Pack URI를 요구하는 프로퍼티를 구현합니다. System.Windows.Application.StartupUri, System.Windows.Controls.Frame.Source, System.Windows.Navigation.NavigationWindow.Source, System.Windows.Documents.Hyperlink.NavigateUri, System.Windows.Window.Icon, 및 System.Windows.Controls.Image.Source.

이 프로퍼티는 마크업과 코드 모두를 사용하여 설정할 수 있습니다.

마크업에서 Pack URI 사용하기

마크업에서, Pack URI의 문자열 값을 가진 어트리뷰트의 엘리먼트를 설정하여 Pack URI를 지정합니다. 예를 들면,

<element attribute="pack://application:,,,/File.xaml" />

다음 표는 마크업에서 문자열 값을 사용하여 지정할 수 있는 각종 절대/상대 Pack URI를 나타냅니다.

표 1: 마크업에서의 절대/상대 Pack URI
(※역주 : 원문에는 표 형태로 되어 있으나 편집의 문제로 항목으로 옮깁니다. 각 항목은 ":"을 중심으로 두 가지 요소로 구분되며 전자는 데이터 파일의 종류를, 후자는 Pack URI 표현을 말합니다.)
리소스 파일 - 로컬 어셈블리 [절대] : "pack://application:,,,/File.xaml"
서브 폴더에 있는 리소스 파일 - 로컬 어셈블리 [절대] : "pack://application:,,,/Subfolder/File.xaml"
리소스 파일 - 참조된 어셈블리 [절대] : "pack://application:,,,/ReferencedAssembly;component/File.xaml"
서브 폴더에 있는 리소스 파일 - 참조된 어셈블리 [절대] : "pack://application:,,,/ReferencedAssembly;component/Subfolder/File.xaml"
리소스 파일 - 버전이 붙은 참조된 어셈블리 [절대] : "pack://application:,,,/ReferencedAssembly;v1.0.0.0;component/File.xaml"
컨텐트 파일 [절대] : "pack://application:,,,/File.xaml"
서브 폴더에 있는 컨텐트 파일 [절대] : "pack://application:,,,/Subfolder/File.xaml"
Site of origin 파일 [절대] : "pack://siteoforigin:,,,/File.xaml"
서브 폴더에 있는 Site of origin 파일 [절대] : "pack://siteoforigin:,,,/Subfolder/File.xaml"
리소스 파일 - 로컬 어셈블리 [상대] : "/File.xaml"
서브 폴더에 있는 리소스 파일 - 로컬 어셈블리 [상대] : "/Subfolder/File.xaml"
리소스 파일 - 참조된 어셈블리 [상대] : "/ReferencedAssembly;component/File.xaml"
서브 폴더에 있는 리소스 파일 - 참조된 어셈블리 [상대] : "/ReferencedAssembly;component/Subfolder/File.xaml"
컨텐트 파일 [상대] : "/File.xaml"
서브 폴더에 있는 컨텐트 파일 [상대] : "/Subfolder/File.xaml"

노트:
Site of origin 파일은 오직 절대 Pack URI로만 참조가 가능합니다.

코드에서 Pack URI 사용하기

코드에서, Uri 클래스를 인스턴스화 하고 Pack URI를 생성자의 파라미터로 전달하여 Pack URI를 지정합니다. 이것은 다음의 예제에서 시연됩니다.

C#
Uri uri = new Uri("pack://application:,,,/File.xaml");

기본적으로, Uri 클래스는 절대 Uri로 참조되었다고 생각합니다. 따라서, 다음과 같이 상대 Pack URI를 참조하는 Uri 클래스의 인스턴스를 사용하려고 시도할 때 예외가 발생합니다.

C#
Uri uri = new Uri("/File.xaml");

운 좋게도, Uri 클래스 생성자 중 하나는 Pack URI가 절대인지 상대인지를 지정할 수 있는 UriKind{http://msdn2.microsoft.com/en-us/library/system.urikind.aspx} 형의 파라미터를 받아들입니다.

C#
// 절대 URI(기본)
Uri absoluteUri = new Uri("pack://application:,,,/File.xaml", UriKind.Absolute);
// 상대 URI
Uri relativeUri = new Uri("/File.xaml", UriKind.Relative);

제공할 Pack URI는 AbsoluteRelative중 하나로 확정하여 지정해야 합니다. 그러나, 어떤 상황에서는 Pack URI가 절대인지 상대인지 컴파일 시점에서는 알 수 없는 경우가 있을 것입니다. 예를 들어 애플리케이션이 런타임에 Pack URI가 절대나 상대가 될 수 있는 사용자 제공의 Pack URI를 수용할 수도 있습니다. 이 경우, RelavieOrAbsolute를 대신 사용할 수 있습니다.

C#
// 상대 또는 절대 URI
TextBox userProvidedTextBox = new TextBox();
Uri uri = new Uri(userProvidedUriTextBox.Text, UriKind.RelativeOrAbsolute);

다음 표는 코드에서 System.Uri를 사용하여 지정할 수 있는 각종 절대/상대 Pack Uri를 나타냅니다.

표2: 코드에서의 상대/절대 Pack URI
(※역주 : 표1과 같은 방법으로 표시합니다.)

리소스 파일 - 로컬 어셈블리 [절대] : Uri uri = new Uri("pack://application:,,,/File.xaml", UriKind.Absolute");
서브 폴더에 있는 리소스 파일 - 로컬 어셈블리 [절대] : Uri uri = new Uri("pack://application:,,,/Subfolder/File.xaml", UriKind.Absolute");
리소스 파일 - 참조된 어셈블리 [절대] : Uri uri = new Uri("pack://application:,,,/ReferencedAssembly;component/File.xaml", UriKind.Absolute");
서브 폴더에 있는 리소스 파일 - 참조된 어셈블리 [절대] : Uri uri = new Uri("pack://application:,,,/ReferencedAssembly;component/Subfolder/File.xaml", UriKind.Absolute");
리소스 파일 - 버전이 붙은 참조된 어셈블리 [절대] : Uri uri = new Uri("pack://application:,,,/ReferencedAssembly;v1.0.0.0;component/File.xaml", UriKind.Absolute");
컨텐트 파일 [절대] : Uri uri = new Uri("pack://application:,,,/File.xaml", UriKind.Absolute");
서브 폴더에 있는 컨텐트 파일 [절대] : Uri uri = new Uri("pack://application:,,,/Subfolder/File.xaml", UriKind.Absolute");
Site of origin 파일 [절대] : Uri uri = new Uri("pack://siteoforigin:,,,/File.xaml", UriKind.Absolute");
서브 폴더에 있는 Site of origin 파일 [절대] : Uri uri = new Uri("pack://siteoforigin:,,,/Subfolder/File.xaml", UriKind.Absolute");
리소스 파일 - 로컬 어셈블리 [상대] : Uri uri = new Uri("/File.xaml", UriKind.Relative");
서브 폴더에 있는 리소스 파일 - 로컬 어셈블리 [상대] : Uri uri = new Uri("/Subfolder/File.xaml", UriKind.Relative");
리소스 파일 - 참조된 어셈블리 [상대] : Uri uri = new Uri("/ReferencedAssembly;component/File.xaml", UriKind.Relative");
서브 폴더에 있는 리소스 파일 - 참조된 어셈블리 [상대] : Uri uri = new Uri("/ReferencedAssembly;component/Subfolder/File.xaml", UriKind.Relative");
컨텐트 파일 [상대] : Uri uri = new Uri("/File.xaml", UriKind.Relative");
서브 폴더에 있는 컨텐트 파일 [상대] : Uri uri = new Uri("/Subfolder/File.xaml", UriKind.Relative");

노트:
Site of origin 파일은 오직 절대 Pack URI로만 참조가 가능합니다.

See Also

Concepts
WPF Application Data Files
Other Resources
Pack URI Sample

신고
Posted by gongdo

MSDN : http://msdn2.microsoft.com/en-us/library/aa970494.aspx

WPF Application Data Files

마이크로소프트 윈도 애플리케이션은 빈번히 XAML, 이미지, 비디오 및 오디오와 같은 비실행 데이터를 포함하는 파일들에 의존합니다. WPF는 설정, 식별 및 애플리케이션 데이터 파일이라고 불리는 이런 종류의 데이터 파일들을 사용하기 위한 특별한 지원을 제공합니다. 이 지원은 다음과 같은 애플리케이션 데이터 파일 종류의 특정한 세트를 주로 다룹니다.

  • Resource 파일 : 실행가능한 또는 라이브러리 WPF 어셈블리에 포함되어 컴파일되는 데이터 파일
  • Content 파일 : 실행가능한 XAML 어셈블리와 명시적인 연결을 갖는 독립적인 데이터 파일
  • Site of Origin 파일(※적당한 번역이 생각나지 않아 site of origin으로 표기합니다.) : 실행가능한 XAML 어셈블리와 관계 없는 독립적인 데이터 파일

이 세가지 종류를 만들기 위한 한가지 중요한 구분은 리소스 파일과 컨텐트 파일은 빌드 시점에 알려지고 어셈블리는 명시적으로 그들을 파악한다는 것입니다. 그러나, site of origin 파일의 경우 어셈블리는 그 파일에 대해 아무런 정보도 가지고 있지 않거나 Pack URI(Uniform Resource Identifier)를 통해 암시적인 정보를 가질 것이고, 후자의 경우는 참조된 site of origin 파일의 존재에 대한 보증이 없습니다.

애플리케이션의 데이터 파일을 참조하기 위해, WPF는 WPF에서의 Pack URI에 상세히 설명된 Pack URI 스키마를 사용합니다.

이 토픽은 애플리케이션 데이터 파일을 어떻게 설정하고 사용하는지에 대해 설명합니다.

이 토픽은 다음 섹션을 담고 있습니다.

리소스 파일

만약 애플리케이션 데이터 파일이 애플리케이션에게 항상 사용 가능해야 한다면, 사용 가능함을 보증할 수 있는 유일한 방법은 애플리케이션의 메인 실행 어셈블리 또는 그것의 참조된 어셈블리 중 하나에 넣어 컴파일하는 것입니다. 이런 애플리케이션 데이터 파일의 종류는 리소스 파일이라고 알려져 있습니다.

다음의 경우에 리소스 파일을 사용해야 합니다.
어셈블리에 넣어 컴파일된 후 리소스 파일의 내용을 업데이트할 필요가 없을 때.
파일 의존성을 줄여 애플리케이션 배포의 복잡함을 간소화 하고 싶을 때.
애플리케이션 데이터 파일이 지역화될 필요가 있을 때(WPF Globalization and Localization Overview를 참고).

노트:
리소스 사전(탑레벨 엘리먼트처럼 ResourceDictionary를 가진 XAML 파일)은 WPF 리소스 파일이 아닙니다. WPF 리소스 파일이 리소스 사전이 될지라도, 리소스 사전은 리소스 파일이 될 수 없습니다(ResourceDictionary를 참고).
-...도저히 번역 불가... .NET 프레임웍 3.0에서 지원하는 임베디드 리소스를 쓸 수 있다는 얘긴지 없단 얘긴지 모르겠고 당장 중요한 내용은 아니라고 생각됩니다.-

리소스 파일 설정
WPF에서, 리소스 파일은 다음과 같은 Resource 아이템처럼 MSBuild(Microsoft build engine) 프로젝트에 포함됩니다. (※역주 : 다음 코드는 VS의 프로젝트파일(.csproj 또는 .vbproj)를 텍스트 에디터로 열어보면 확인할 수 있습니다. 물론 VS IDE상에서 수정이 가능하므로 직접 수정하는 경우는 거의 없습니다.)

<Project xmlns="http://schemas.microsoft.com/developer/msbuild/2003"
... >
...
<ItemGroup>
<Resource Include="ResourceFile.xaml" />
</ItemGroup>
...
</Project>

노트:
마이크로소프트 비주얼 스튜디오 2005에서, 파일을 프로젝트에 추가하고 Resource에 그것의 Build Action을 설정하여 리소스 파일을 추가할 수 있습니다.

프로젝트가 빌드되었을 때, MSBuild는 리소스를 어셈블리로 컴파일합니다.

리소스 파일 사용
리소스 파일을 로드하기 위해, 원하는 리소스 파일을 식별하는 Pack URI를 전달하는 Application 클래스의 GetResourceStream을 호출할 수 있습니다. GetResourceStream은 리소스 파일을 Stream으로 노출하고 그것의 컨텐트 종류를 설명하는 StreamResourceInfo 객체를 반환합니다.

예를 들어, 다음 코드는 어떻게 GetResourceStream을 사용하여 Page 리소스 파일과 Frame의 컨텐츠로 그것을 설정하는지를 보여줍니다.

C#
// Navigate to xaml page
Uri uri = new Uri("/PageResourceFile.xaml", UriKind.Relative);
StreamResourceInfo info = Application.GetResourceStream(uri);
System.Windows.Markup.XamlReader reader = new System.Windows.Markup.XamlReader();
Page page = (Page)reader.LoadAsync(info.Stream);
this.pageFrame.Content = page;

GetResourceStream호출이 Stream으로의 접근을 제공할 때, 그것과 함께 세팅할 프로퍼티의 종류로 그것을 변환하는 추가적인 작업이 필요합니다. 아니면, 코드를 사용하여 프로퍼티에 직접 리소스 파일을 로딩하여 WPF가 Stream 열기와 변환을 관리하도록 할 수 있습니다.

다음 예제는 코드를 사용하여 FramePage를 직접 로딩하는 방법을 보여줍니다.

C#
Uri pageUri = new Uri("/PageResourceFile.xaml", UriKind.Relative);
this.pageFrame.Source = pageUri;

다음 예제는 전의 예제와 동일한 마크업입니다.

XAML
<Frame Name="pageFrame" Source="PageResourceFile.xaml" />

리소스 파일로서의 애플리케이션 코드 파일
WPF 애플리케이션 코드 파일의 특별한 세트는 윈도, 페이지, 플로우 문서 및 리소스 사전을 포함하는 Pack URI를 사용하여 참조될 수 있습니다. 예를 들어, System.Windows.Application.StartupUri 속성을 애플리케이션이 시작할 때 로드할 윈도나 페이지를 참조하는 Pack URI로 설정할 수 있습니다.

XAML
<Application
    xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
    StartupUri="MainWindow.xaml">
</Application>

이는 XAML 파일이 MSBuild 프로젝트에 Page 아이템으로 포함되었을 때 가능합니다.

<Project xmlns="http://schemas.microsoft.com/developer/msbuild/2003"
... >
...
<ItemGroup>
<Page Include="MainWindow.xaml" />
</ItemGroup>
...
</Project>
노트:
마이크로소프트 비주얼 스튜디오 2005에서, 새 Window, NavigationWindow, Page, FlowDocument 혹은 ResourceDictionary를 프로젝트에 추가하면, 마크업 파일을 위한 Build Action은 기본적으로 Page가 될 것입니다.

Page 아이템이 있는 프로젝트가 컴파일되었을 때, XAML 아이템은 바이너리 포맷으로 변환되고 연관된 어셈블리에 포함되어 컴파일됩니다. 따라서, 이 파일은 일반적인 리소스 파일과 같은 방법으로 사용할 수 있습니다.

노트:
XAML 파일이 Resource 아이템으로 설정되었고, 코드-비하인드 파일을 가지지 않는다면, XAML의 바이너리 버전이 아닌 생(raw) XAML이 어셈블리에 포함되어 컴파일됩니다.

컨텐트 파일

content file은 실행 어셈블리와 나란히 느슨한 파일(loose file)로 배포됩니다. 파일이 어셈블리에 포함되어 컴파일되지 않더라도, 어셈블리는 각 컨텐트 파일에 대한 관계를 맺는 메타데이터로 컴파일됩니다.

애플리케이션이 그들을 소비하는 어셈블리를 재컴파일하지 않고도 업데이트할 수 있는 애플리케이션 데이터 파일의 특정한 세트가 필요할 경우 반드시 컨텐트 파일을 사용해야 합니다.

컨텐트 파일 설정
프로젝트에 컨텐트 파일을 추가하기 위해, 애플리케이션 데이터 파일은 반드시 Content 아이템으로 포함되어야 합니다. 게다가, 컨텐트 파일은 어셈블리로 직접 컴파일되지 않으므로, MSBuild CopyToOutputDirectory 메타데이터 엘리먼트를 컨텐트 파일이 빌드된 어셈블리와 관계되어 복사될 위치로 정의하도록 설정할 필요가 있습니다. 프로젝트가 빌드될 때마다 리소스가 빌드 출력 폴더에 복사되기를 원한다면, CopyToOutputDirectory 메타데이터 엘리먼트를 Always 값으로 설정합니다. 그외의 경우, PreserveNewest 값을 사용하여 리소스의 새 버전이 있을 때만 빌드 출력 폴더에 복사할 수 있습니다.

다음은 컨텐트 파일을 프로젝트에 리소스의 새 버전이 추가되었을 때 빌드 출력 폴더에 복사하는 설정의 파일을 보여줍니다.

<Project xmlns="http://schemas.microsoft.com/developer/msbuild/2003"
... >
...
<ItemGroup>
<Content Include="ContentFile.xaml">
<CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
</Content>
</ItemGroup>
...
</Project>
노트:
마이크로소프트 비주얼 스튜디오 2005에서, 컨텐트 파일을 프로젝트에 파일을 추가하고 그것의 Build ActionContent로 설정하고, 그것의 Copy to Output DirectoryCopy Always(=Always)와 Copy if newer(=PreserveNewest)로 설정하여 생성합니다.

프로젝트가 빌드되었을 때, 다음과 같이 AssemblyAssociatedContentFileAttribute 어트리뷰트가 각 컨텐트 파일을 위해 어셈블리의 메타데이터로 컴파일됩니다.

[assembly: AssemblyAssociatedContentFile("ContentFile.xaml")]

AssemblyAssociatedContentFileAttribute의 값은 프로젝트에서 그것의 위치에 관련된 컨텐트 파일의 경로를 암시합니다. 예를 들어, 컨텐트 파일이 프로젝트의 서브폴더에 위치하였다면, 추가 경로 정보는 다음과 같이 AssemblyAssociatedContentFileAttribute 값에 통합될 것입니다.

[assembly: AssemblyAssociatedContentFile("Resources/ContentFile.xaml")]

AssemblyAssociatedContentFileAttribute 값은 빌드 출력 폴더에서 컨텐트 파일의 경로의 값이기도 합니다.

컨텐트 파일의 사용
컨텐트 파일을 로드하기 위해, Application 클래스의 GetContentStream 메소드를 호출 할 수 있습니다. GetContentStream은 컨텐트 파일을 Stream으로 노출하고 그것의 컨텐트 타입을 설명하는 StreamResourceInfo 객체를 반환합니다.

예를 들어, 다음 코드는 GetContentStream을 사용하여 어떻게 Page 컨텐트 파일을 로드하고 Frame의 컨텐트로 설정하는지 보여줍니다.

C#
// Navigate to xaml page
Uri uri = new Uri("/PageContentFile.xaml", UriKind.Relative);
StreamResourceInfo info = Application.GetContentStream(uri);
System.Windows.Markup.XamlReader reader = new System.Windows.Markup.XamlReader();
Page page = (Page)reader.LoadAsync(info.Stream);
this.pageFrame.Content = page;

GetContentStream호출이 Stream으로의 접근을 제공할 때, 그것과 함께 세팅할 프로퍼티의 종류로 그것을 변환하는 추가적인 작업이 필요합니다. 아니면, 코드를 사용하여 프로퍼티에 직접 리소스 파일을 로딩하여 WPF가 Stream 열기와 변환을 관리하도록 할 수 있습니다.

다음 예제는 코드를 사용하여 FramePage를 직접 로딩하는 방법을 보여줍니다.

C#
Uri pageUri = new Uri("/PageContentFile.xaml", UriKind.Relative);
this.pageFrame.Source = pageUri;

다음 예제는 전의 예제와 동일한 마크업입니다.

XAML
<Frame Name="pageFrame" Source="PageContentFile.xaml" />

Site of Origin 파일

리소스 파일은 AssemblyAssociatedContentFileAttribute에 의해 정의되어 함께 배포되는 어셈블리와 명시적인 관계를 가집니다. 하지만, 다음과 같은 경우를 포함하는 암묵적이거나 어셈블리와 애플리케이션 데이터 파일간의 관계가 없는 초기화를 원하는 경우도 있습니다.

  • 파일이 컴파일 시점에 존재하지 않을 때.
  • 어셈블리가 런타임이 될때까지 파일을 필요로 하지 않을 때.
  • 연관된 어셈블리를 재컴파일 하지 않고 파일을 업데이트하고 싶을 때.
  • 애플리케이션이 오디오나 비디오 처럼 큰 데이터 파일을 사용하고 사용자의 선택에 따라 그것을 다운로드하길 원할 때.

이는 file:///http:// 스키마와 같은 전통적인 URI 스키마를 통해 이런 파일의 타입을 로드할 수 있습니다.

XAML
<Image Source="file:///C:/DataFile.bmp"></Image>
<Image Source="http://www.datafilewebsite.com/DataFile.bmp"></Image>

그러나, file:///http:// 스키마는 애플리케이션에게 완전한 신뢰(full trust)를 요구합니다. 만약 애플리케이션이 인터넷이나 인트라넷에서 시작된 XAML 브라우저 애플리케이션(XBAPs)라면, 그것은 그 위치에서 시작된 애플리케이션을 위해 허용된 허가(permissions)의 세트에 대해서만 요청하고, 느슨한 파일은 애플리케이션의 시작점(site of origin, 시작된 위치)에서만 로드할 수 있습니다. 이런 파일들은 site of origin파일이라고 합니다.

Site of origin 파일은 제한이 없는 부분적으로 신뢰된 애플리케이션이더라도 부분적으로 신뢰된 애플리케이션이 선택할 수 있는 유일한 옵션입니다. 완전히 신뢰된 애플리케이션은 여전히 빌드 시점에 확인하지 못한 애플리케이션 데이터 파일 로드를 필요로 할지도 모릅니다. 완전히 신뢰된 애플리케이션은 file:///을 사용할 수 있고, 아마도 애플리케이션 데이터 파일은 같은 폴더나 애플리케이션 어셈블리의 서브 폴더에 설치될 것입니다.
이 경우 site of origin 참조를 사용하는 것은 file:///을 사용하는 것보다 쉽습니다. 왜냐하면, file:///은 파일을 full 경로로 표기할 것을 요구하기 때문입니다.

노트:
Site of origin 파일은 컨텐트 파일이 클라이언트 머신의 XAML 브라우저 애플리케이션(XBAP)에 있을 때는 캐쉬되지 않습니다. 따라서, 그들은 특수한 요청이 있을 때만 다운로드 됩니다. 만약 XAML 브라우저 애플리케이션(XBAP) 애플리케이션이 커다란 미디어 파일을 가진다면, 그것들을 site of origin 파일로 설정한다는 것은 애플리케이션 초기화가 더 빨라진다는 것을 의미하고, 꼭 필요할 때에만 다운로드된다는 것을 말합니다.

Site of Origin 파일 설정
site of origin 파일이 존재하지 않거나 컴파일 시점에 알 수 없다면, XCopy 커맨드 라인 프로그램이나 Microsoft Windows Installer를 포함한 런타임 중 요청된 파일이 사용 가능함을 확실히 하기 위한 전통적인 개발 매커니즘을 사용할 필요가 있습니다.

컴파일 시점에 site of origin에 위치하길 원하는 파일을 알고 있지만, 여전히 명시적인 의존성을 피하고 싶다면, 이 파일들을 None 아이템으로 MSBuild 프로젝트에 추가할 수 있습니다. 컨텐트 파일과 같이 MSBuild CopyToOutputDirectory 어트리뷰트를 AlwaysPreserveNewest로 지정하여 빌드된 어셈블리와 관련하여 site of origin파일이 복사될 위치로 지정하는 설정이 필요합니다.

<Project xmlns="http://schemas.microsoft.com/developer/msbuild/2003"
... >
...
<None Include="PageSiteOfOriginFile.xaml">
<CopyToOutputDirectory>Always</CopyToOutputDirectory>
</None>
...
</Project>
Note:
마이크로소프트 비주얼 스튜디오 2005에서는, 파일을 프로젝트에 추가하고 그것의 Build ActionNone으로 설정하여 site of origin 파일을 추가합니다.

Site of Origin 파일 사용
site of origin 파일을 로드하기 위해, 원하는 site of origin 파일을 식별하는 Pack URI를 전달하는 Application 클래스의 GetRemoteStream 메소드를 호출할 수 있습니다.
GetRemoteStream은 site of origin 파일을 Stream으로 노출하고 그것의 컨텐트 타입을 설명하는 StreamResourceInfo 객체를 반환합니다.

예를 들어, 다음 코드는 GetRemoteStream을 사용하여 어떻게 Page 컨텐트 파일을 로드하고 Frame의 컨텐트로 그것을 설정하는지 보여줍니다.

C#
// Navigate to xaml page
Uri uri = new Uri("/SiteOfOriginFile.xaml", UriKind.Relative);
StreamResourceInfo info = Application.GetRemoteStream(uri);
System.Windows.Markup.XamlReader reader = new System.Windows.Markup.XamlReader();
Page page = (Page)reader.LoadAsync(info.Stream);
this.pageFrame.Content = page;

GetRemoteStream호출이 Stream으로의 접근을 제공할 때, 그것과 함께 세팅할 프로퍼티의 종류로 그것을 변환하는 추가적인 작업이 필요합니다. 아니면, 코드를 사용하여 프로퍼티에 직접 리소스 파일을 로딩하여 WPF가 Stream 열기와 변환을 관리하도록 할 수 있습니다.

다음 예제는 코드를 사용하여 Frame에 Page를 직접 로딩하는 방법을 보여줍니다.

C#
Uri pageUri = new Uri("pack://siteoforigin:,,,/Subfolder/SiteOfOriginFile.xaml", UriKind.Absolute);
this.pageFrame.Source = pageUri;

다음 예제는 전의 예제와 동일한 마크업입니다.

XAML
<Frame Name="pageFrameSOO" Source="pack://siteoforigin:,,,/PageContentFile.xaml" />
XAML
<Frame Name="pageFrame" Source="pack://siteoforigin:,,,/SiteOfOriginFile.xaml" />

빌드 타입이 변경된 후 다시 빌드하기

애플리케이션 데이터 파일의 빌드 타입을 변경한 후에는, 그 변경을 올바로 적용하기 위해 해당 애플리케이션을 다시 빌드할 필요가 있습니다. 단지 애플리케이션만 빌드하는 경우라면, 변경 사항은 적용되지 않습니다.

See Also

Cencepts
Pack URIs in Windows Presentation Foundation

신고
Posted by gongdo
MSDN : http://msdn2.microsoft.com/en-us/library/ms743714.aspx

Application Management Overview

이 토픽은 Application 클래스를 소개하는 것으로 시작해 Application에 의해 제공되는 애플리케이션, 애플리케이션의 라이프타임 및 부가 서비스를 어떻게 정의하는가와 같은 서비스의 개요를 제공합니다.

이 토픽은 다음 섹션과 같은 내용을 담고 있습니다. 애플리케이션 클래스 The Application Class

WPF에서, 애플리케이션은 Application 클래스로 캡슐화됩니다. Application은 다음과 같은 기능의 서비스를 제공합니다.
  • 공통 애플리케이션 기반(infrastructure)을 생성하고 관리
  • 애플리케이션 라이프타임에 상호 작용하고 추적
  • 커맨드 라인 파라미터를 받고 처리
  • 애플리케이션 스코프 속성과 리소스를 공유
  • 핸들되지 않은 예외를 검출하고 반응
  • 종료 코드를 반환
  • 독립 애플리케이션들의 윈도들을 관리(MSDN : WPF Windows Overview 참고)
  • XAML 브라우저 애플리케이션(XBAPs)에서의 내비게이션 및 내비게이션 윈도와 프레임을 가진 독립 애플리케이션의 추적(MSDN : Navigation Overview 참고)

애플리케이션 구현

일반적인 WPF 애플리케이션은 마크업과 코드-비하인드 모두를 사용하여 정의됩니다. 이것은 마크업을 사용하여 선언적으로 애플리케이션 속성, 리소스 및 이벤트 등록을 설정할 수 있게 하고, 이벤트를 처리할 때 코드-비하인드에서 특정한 동작을 구현합니다. 다음 예제는 어떻게 마크업과 코드-비하인드를 모두 사용하여 애플리케이션을 정의하는지를 보여줍니다.

XAML

<Application

    xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"

    xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"

    x:Class="App" />

C#
using System.Windows;
public partial class App : Application
{
    public App()
    {
        InitializeComponent();
    }
}

마크업 파일과 코드-비하인드 파일을 함께 사용하기 위해서 다음의 사항이 필요합니다.

  • 마크업에서, Application 엘리먼트는 반드시 x:Class 어트리뷰트에 의해 정의되는 이름으로 프로젝트가 빌드될 때 마크업 파일을 위해 partial class를 만들기 위한 MSBuild를 구성하는 x:Class 어트리뷰트를 포함해야 합니다. 이것은 XAML 스키마(xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml")를 위한 XML 네임스페이스 선언의 추가를 요구합니다. 부분적으로 생성된 partial class는 이벤트 등록과 마크업에서 구현된 프로퍼티의 설정을 위해 호출되는 InitializeComponent를 구현합니다.
  • 코드-비하인드에서, 클래스는 반드시 마크업에서 x:Class 어트리뷰트로 지정된 partial class와 같은 이름이어야 하고, Application을 상속할 필요가 있습니다. 이는 코드-비하인드 파일이 빌드될 때 마크업 파일을 위해 생성된 partial class와 연결되는 것을 가능케합니다(WPF 애플리케이션 빌드하기 참고).
  • 코드-비하인드에서, 클래스는 반드시 마크업에서 x:Class로 설정된 같은 이름의 partial class로 정의되어야 합니다. 이것은 코드-비하인드 파일이 프로젝트가 빌드될 때 마크업 파일을 위해 생성된 partial class와 연결되는 것을 가능케 합니다(WPF 애플리케이션 빌드하기 참고).
노트:
Microsoft Visual Studio를 사용하여 새 Windows Application(WPF)나 XAML 브라우저 애플리케이션(WPF)프로젝트를 생성할 때, 애플리케이션 정의는 기본적으로 마크업과 코드-비하인드를 모두 포함합니다.

이 최소한의 애플리케이션 정의는 WPF 애플리케이션 작업으로 생성하기 위해 작성할 필요가 있는 코드의 전부입니다. 그러나, 애플리케이션 정의는 특정한 방법의 MSBuild를 위해 설정될 필요가 있습니다.

MSBuild를 위한 애플리케이션 정의 설정

모든 WPF 실행 애플리케이션(독립적인 애플리케이션과 XBAP)은 실행하기 위한 기반(infrastructure)의 어떤 레벨의 구현이 필요합니다. 먼저, 이것은 애플리케이션을 시작시키기 위해 OS가 호출하는 함수로 유명한 엔트리 포인트 함수를 포함합니다. 전통적으로 개발자는 전부는 아니더라도 그것을 위한 코드의 어느 정도를 작성해야 했습니다. 그러나, WPF는 MSBuild ApplicationDefinition 아이템과 같은 애플리케이션 정의 마크업 파일을 설정하는 것에 의해 이 코드를 생성할 것입니다. 필요한 설정은 다음 예제에서 보여줍니다. (※역주 : 다음의 코드는 VS2005의 프로젝트 파일(.csproj또는 .vbproj)를 텍스트 편집기에서 열어 확인할 수 있습니다. 물론 일반적인 경우 이 코드를 직접 수정하는 경우는 없습니다.)

<Project DefaultTargets="Build"
xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
...
<ApplicationDefinition Include="App.xaml" />
<Compile Include="App.xaml.cs" />
...
</Project>

여기에서, 코드-비하인드 파일은 MSBuild의 Compile 아이템에 의해 설정됩니다. 또한, 코드-비하인드 파일은 추가적인 언어 정의 접미어(.cs.vb)가 붙은 마크업 파일과 같은 이름을 가지고 있습니다. 이 접미어는 Microsoft Visual Studio가 기본적으로 이 규칙을 사용하긴 하지만 반드시 필요한 것은 아닙니다.

노트:
WPF 애플리케이션 작성의 자세한 사항은, WPF 애플리케이션 만들기를 참조합니다.

애플리케이션 정의와 MSBuild 설정과의 조합의 효과는 MSBuild가 다음과 같은 코드를 생성하게 합니다.

C#
public class App : Application
{
    public App() { }
    [STAThread]
    public static void Main()
    {
        App app = new App();
        app.InitializeComponent();
        app.Run();
    }

    public void InitializeComponent()
    {
        // Register XAML-declared events
        ...
        // Set XAML-declared properties
        ...
    }
}

이 애플리케이션이 시작되었을 때, 윈도는 엔트리 포인트 함수(C#과 Visual Basic 모두 Main)를 호출할 것입니다. 이후, 엔트리 포인트 함수는 이벤트 등록과 마크업에서 구현된 속성 설정을 위한 InitializeComponent를 호출하기 전에 사용자 애플리케이션 클래스의 새 인스턴스를 생성합니다.

거의 대부분, AppDomain별로 단 하나의 Application 클래스나 서브클래스의 인스턴스만이 존재합니다. 이 때문에, 애플리케이션-스코프 속성과 리소스(나중에 다룹니다)의 단일 셋으로의 공유 접근을 지원하기 위해, Application은 싱글톤 패턴을 사용하여 구현됩니다. 싱글톤 패턴은 싱글톤(C#에서 싱글톤 구현하기 참고)이라고 알려진 단 하나의 인스턴스만을 가지는 클래스 생성을 위한 모델입니다. 싱글톤 클래스는 static 속성으로 공유 접근을 제공하는 자신의 인스턴스를 만듭니다. Application 클래스를 위한 이 속성은 다음과 같은 Current입니다.

C#
// Get reference to application
App currentApp = (App)Application.Current;

생성된 코드에서, App가 인스턴스화된 이후 호출되는 Run 메소드를 알 수 있을 것입니다. 이것은 WPF 애플리케이션의 생명이 시작된다는 것을 말합니다.

노트:
실행 애플리케이션의 단 하나의 인스턴스가 실행될 것을 검출할 필요가 있을 때를 포함하여, 이 코드를 직접 작성할 필요가 있는 상황이 있습니다. 더 자세한 정보는 단일 인스턴스 검출 샘플을 참고합니다.

애플리케이션 라이프타임

System.Windows.Application.Run이 호출된 후, 애플리케이션이 시작되고, 라이프타임 동안 사용자나 프로그램 조건에 응답하여 최종적으로 실행을 중지하기 전까지 여러번 비활성화와 활성화할 것입니다.

애플리케이션 시작하기
System.Windows.Application.Run
이 호출된 후, Application은 모든 애플리케이션에서 공통적으로 필요한 기반의 셋을 초기화합니다. 기반이 구축될 때, Application은 WPF 애플리케이션이 시작되는 순간을 의미하는 Startup 이벤트를 발생시킵니다.

XAML
<Application
    xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
    xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
    x:Class="App"
    Startup="App_Startup" />
C#
public partial class App : Application
{
   
void App_Startup(object sender, StartupEventArgs e)
    {
       
// Application is running
    }
}

MSBuild ApplicationDefinition 아이템과 같은 애플리케이션 정의를 구현할 때 시작(launching), 실행(running) 및 애플리케이션 기반의 초기화(establishing) 작업이 WPF에 의해 작동됩니다. 이것은 대부분 애플리케이션의 시작을 위해 항상 필요한 UI 보여주기와 커맨드라인 매개 변수 처리를 포함하는 기능 구축에 집중할 수 있게 합니다.

유저 인터페이스 보여주기
대부분의 윈도 애플리케이션은 유저 인터페이스를 열기 때문에 실행을 시작할 때 Startup 이벤트 핸들러는 그것을 수행하기에 적합한 위치입니다. 독립적인 애플리케이션을 위해, 이것은 다음과 같이 윈도를 보여주는것에 관계됩니다.

C#
public partial class App : Application
{
    void App_Startup(object sender, StartupEventArgs e)
    {
        // Application is running

        // Show the main window
        MainWindow mainWindow = new MainWindow();
        mainWindow.Show();
    }
}

단지 Startup을 처리하는 것이 윈도를 보여주기 위한 것이라면, 대신에 마크업에서 StartupUri를 설정할 수 있습니다.

XAML
<Application
    xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
    xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
    x:Class="App"
    StartupUri="MainWindow.xaml" />

독립 애플리케이션의 UI가 윈도 대신에 페이지(Page)의 조합일 경우에도, StartupUri를 시작 페이지로 설정하는데 사용할 수 있습니다.

XAML
<Application
    xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
    xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
    x:Class="App"
    StartupUri="HomePage.xaml" />

XBAP 애플리케이션에서도, StartupUri을 사용하여 윈도 Internet Explorer에서 보여줄 첫번째 페이지를 지정할 수 있습니다.

UI를 보여주는 것에 관하여 StartupUri를 세팅하는 대신 Startup처리가 필요가 있는 주 원인은 기본 생성자를 사용하지 않거나 UI를 보여주기 전에 속성을 설정하는 것을 구현하는 클래스를 인스턴스화하기 위해서 입니다.

애플리케이션에서 커맨드라인 매개 변수를 받아서 처리하기 위해서도 Startup을 처리할 필요가 있을 것입니다.

커맨드라인 매개 변수 처리하기
윈도에서, 독립 애플리케이션은 커맨드 프롬프트나 데스크탑에서 시작될 수 있습니다. 두 경우 모두, 커맨드라인 매개 변수를 다음과 같은 문법을 사용하여 애플리케이션에 전달할 수 있습니다.

wpfapplication.exe /winstate:maximized

애플리케이션이 초기화하는 동안, WPF는 OS로부터 커맨드라인 매개 변수를 받고 그것을 StartupEventArgs 파라미터의 Args 프로퍼티를 통해 Startup 이벤트 핸들러에 전달합니다. 다음과 같은 코드를 사용하여 커맨드라인 매개 변수를 받아 저장할 수 있습니다. (※역주 : 다음 코드는 원문에서 XAML과 C#으로 나뉘어 있지 않고 XAML이라고만 표시되어 있는데 내용상 C#으로 분리해야 맞다고 생각됩니다. 또한 이후에도 두세번 이런 코드가 있는데 모두 XAML과 C#으로 분리하였습니다.)

XAML
<Application
    xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
    xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
    x:Class="App"
    StartupUri="MainWindow.xaml"
    Startup="App_Startup" />
C#

using System;
using System.Collections;
using System.Text.RegularExpressions;
using System.Windows;

public partial class App : Application

{

    // Indexed command line args using hash table

    public static Hashtable CommandLineArgs = new Hashtable();


    void App_Startup(object sender, StartupEventArgs e)

    {

        // Don't bother if no command line args were passed

        // NOTE: e.Args is never null - if no command line args were passed,

        //       the length of e.Args is 0.

        if (e.Args.Length == 0) return;


        // Parse command line args for args in the following format:

        //   /argname:argvalue /argname:argvalue /argname:argvalue ...

        //

        // Note: This sample uses regular expressions to parse the command line arguments.

        // For regular expressions, see:

        // http://msdn.microsoft.com/library/en-us/cpgenref/html/cpconRegularExpressionsLanguageElements.asp

        string pattern = @"(?<argname>/\w+):(?<argvalue>\w+)";

        foreach (string arg in e.Args)

        {

        Match match = Regex.Match(arg, pattern);


        // If match not found, command line args are improperly formed.

        if (!match.Success) throw new ArgumentException("The command line arguments are improperly formed. Use /argname:argvalue.");


        // Store command line arg and value

        CommandLineArgs[match.Groups["argname"].Value] = match.Groups["argvalue"].Value;

    }

}

 

노트:
자세한 정보는 커맨드라인 매개 변수 처리하기 샘플을 참고합니다.

애플리케이션 활성화와 비활성화
애플리케이션의 라이프타임 동안, 사용자는 그것과 현재 실행중인 다른 애플리케이션 사이의 전환을 할 것입니다. 사용자가 다른 애플리케이션의 윈도 중 하나를 활성화하여 전환하는 시점에 현재 애플리케이션은 비활성화됩니다. 이 상황은 Deactivated를 처리하여 검출할 수 있습니다. 반대로, 사용자가 다시 애플리케이션의 윈도 중 하나를 선택하면, 애플리케이션은 활성화되고 따라서, Activated가 발생됩니다. ActivatedDeactivated 모두 다음과 같이 처리될 수 있습니다.

XAML
<Application
  xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
  xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
  x:Class="App"
  StartupUri="MainWindow.xaml"
  Activated="App_Activated"
  Deactivated="App_Deactivated" />
C#
using System;

using System.Windows;

public partial class App : Application

{

    bool isApplicationActive;


    void App_Activated(object sender, EventArgs e)

    {

        // Activated

        this.isApplicationActive = true;

    }


    void App_Deactivated(object sender, EventArgs e)

    {

        // Deactivated

        this.isApplicationActive = false;

    }

}

각 윈도 별로 활성화와 비활성화를 처리할 필요가 있다면, 전체 애플리케이션 대신, System.Windows.Window.ActivatedSystem.Windows.Window.Deactivated를 처리할 수 있습니다.

처리되지 않은 예외
애플리케이션이 실행되고 있을 때, 애플리케이션 코드는 예상치 못한 잠재적으로 처리되지 않은 예외를 던질 수 있습니다. 기본적으로 .NET Framework 3.0은 애플리케이션이 다운되기 전에 다음 그림과 같은 알림을 사용자에게 보여주는 것으로 처리되지 않은 예외에 응답합니다.

사용자 삽입 이미지

유저 경험의 관점에서, 애플리케이션이 다음 항목의 일부 혹은 전부를 수행하여 기본 동작을 피하는 것이 더 낫습니다.

  • 처리되지 않은 예외를 검출하기 위한 공통적인 메카니즘을 제공.
  • 사용자에게 더욱 설명적인 정보를 제공.
  • 애플리케이션이 계속 실행되도록 시도.
  • 일반적으로 윈도 이벤트 로그에 설명적인 정보를 로깅.

이 지원을 구현하는 것은 다음과 같이 DispatcherUnhandledException이 발생하여 처리되지 않은 예외를 검출할 수 있게 되는 것에 달려있습니다.

XAML
<Application
    xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
    xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
    x:Class="App"
    StartupUri="MainWindow.xaml"
    DispatcherUnhandledException="App_DispatcherUnhandledException" />
C#
public partial class App : Application

{

    void App_DispatcherUnhandledException(object sender, DispatcherUnhandledExceptionEventArgs e)

    {

        // Process unhandled exception

        ...

        // Prevent default unhandled exception processing

        e.Handled = true;

    }

}

DispatcherUnhandledException 이벤트 핸들러는 예외 자신(System.Windows.Threading.DispatcherUnhandledExceptionEventArgs.Exception)을 포함하여 처리되지 않은 예외에 관한 컨텍스트 정보를 담고있는 DispatcherUnhandledExceptionEventArgs 파라미터로 전달됩니다. 이 정보를 사용하여 예외가 복구가능한지 아닌지를 결정할 수 있습니다. 복구 가능한 예외의 예를 들자면 FileNotFoundException이 있고, 복구 불가능한 예외의 예는 StackOverflowException가 있습니다.

언제든 DispatcherUnhandledExecption을 처리할 때는, 반드시 System.Windows.Threading.DispatcherUnhandledExceptionEventArgs.Handled 프로퍼티를 true(※역주 : MSDN에는 false로 나와있는데 문맥상 true가 맞다고 생각됩니다.)로 설정해야 합니다. 그렇지 않으면, WPF는 여전히 예외가 처리되지 않았다고 생각하여 기본 동작으로 애플리케이션을 종료합니다.

노트:
처리되지 않은 예외가 발생하였고 DispatcherUnhandledException 이벤트가 처리되지 않거나 이벤트가 Handledfalse로 설정하여 처리되었다면, 애플리케이션은 곧바로 종료될 것입니다. 게다가, Application에 의해 정의된 어떤 이벤트도 발생하지 않습니다. 따라서, 애플리케이션이 애플리케이션의 종료 시점에 실행할 필요가 있는 코드를 가졌다면 DispatcherUnhandledException을 처리할 필요가 있을 것입니다.

상세한 내용은 DispatcherUnhandledExecption 처리하는 것을 보여주는 Unhandled Application Exceptions Sample을 참고합니다.

애플리케이션 종료(Shutdown)
처리되지 않은 예외가 일어났을 때 예외가 여전히 처리되지 않았다면 애플리케이션이 종료될 것입니다. 애플리케이션은 아마도 다음과 같은 경우로 종료되는 경우가 더 많을 것입니다.

  • 사용자에 의해 모든 윈도가 닫혔을 때.
  • 사용자에 의해 메인 윈도가 닫혔을 때.
  • 사용자가 로그 오프나 윈도 종료로 윈도 세션을 끝낼 때.
  • 종료를 의미하는 조건을 만났을 때.

이 모든 경우에, Shutdown메소드가 호출됩니다. Shutdown이 코드에서 호출되는지 WPF에서 호출되는지는 Application 설정을 어떻게 하느냐에 달려있습니다.

종료(Shutdown) 모드
일반적으로, 독립 애플리케이션의 라이프타임은 그것이 보여주는 윈도의 라이프타임을 캡슐화 합니다. 애플리케이션의 종류에따라, 애플리케이션은 모든 윈도가 닫히거나 메인 윈도가 닫혔을 때 종료될 것입니다. 이 두가지 시나리오는 가장 일반적이기 때문에, ShutdownMode를 다음의 ShutdownMode 열거값 중 하나로 설정할 때 Application을 자동으로 종료하도록 설정할 수 있습니다.

예를 들어, 애플리케이션이 메인 윈도가 닫혔을 때 종료되도록 설정하고 싶다면 다음과 같이 하면 됩니다.

XAML
<Application
    xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
    xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
    x:Class="App"
    ShutdownMode="OnMainWindowClose" />
노트:
메인 윈도는 System.Windows.Application.MainWindow 프로퍼티에 의해 참조되는 윈도입니다. 기본적으로 이 프로퍼티의 값은 인스턴스화 된 애플리케이션의 첫번째 윈도를 참조하지만 이 값은 나중에 프로그램에서 변경할 수 있습니다.

ShutdownMode를 설정하는 것은 언제, 누구에 의해 Shutdown이 호출되는지를 명시합니다. ShutdownMode가 OnLastWindowClose나 OnMainWindowClose로 설정한 경우, WPF는 이 열거값 설정에의해 지정된 조건이 특정되었을 때 자동으로 Shutdown 메소드를 호출합니다.

ShutdownModeOnExplicitShutdown으로 설정되었다면, Shutdown을 호출하는 것은 개발자의 책임이고, 그렇지 않을 경우 애플리케이션은 모든 윈도가 닫힌다고 해도 계속 실행될 것입니다.

세션 종료(Ending)
ShutdownMode를 세팅하는 것은 애플리케이션 종료(shutting down)을 위한 내부 메커니즘이며, 애플리케이션은 또한 다음과 같은 외부 조건에 의해 종료될 수 있습니다.
  • 사용자가 윈도를 로그 오프하여 세션이 종료될 때.
  • 사용자가 윈도를 종료하거나 재시작하거나 하이버네이션하여 세션이 종료될 때.

사용자가 세션을 종료할 때, 윈도는 현재 동작중인 각 애플리케이션을 위해 언제 그랬는지 검출하고, 필요하다면 세션이 종료되는 것을 막도록 기회를 줍니다. 사용자가 데이터를 편집할 수 있는 (워드 프로세서나 스프레드 시트와 같은)애플리케이션은 이 기능을 사용하기에 가장 적합합니다. 사용자는 실수로 저장하지 않은 문서를 닫도록 시도할 수도 있고, 예기치 못하게 애플리케이션에 저장하지 않은 문서를 둔 채로 윈도를 종료할 수도 있습니다. 따라서, 애플리케이션은 애플리케이션 데이터가 저장되었는지를 확인할 기회를 사용자에게 줄 수 있고, 아니면 사용자에게 윈도의 종료를 막을 기회를 줄 수 있습니다.

Application은 언제 윈도가 세션 종료 알림을 발생시키는지, SessionEnding 이벤트가 언제 일어났는지를 검출합니다. SessionEnding을 처리하여 다음과 같이 검출하고, 응답하고, 세션 종료를 취소할 수 있습니다.

XAML
<Application
    xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
    xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
    x:Class="App"
    SessionEnding="App_SessionEnding" />
C#

public partial class App : Application

{

    void App_SessionEnding(object sender, SessionEndingCancelEventArgs e)

    {

        using (StreamWriter writer = File.AppendText("output.txt"))

        //using (FileStream stream = File.AppendText("output.txt"))

        //using (StreamWriter writer = new StreamWriter(stream))

        {

            writer.WriteLine("OnSessionEnding");

        }


        // Ask the user if they want the session to end

        string msg = "The application is shutting down for the following reason: " + e.ReasonSessionEnding + "\n\nShutdown?";

        string title = "An Application";

        MessageBoxButton buttons = MessageBoxButton.YesNo;

        MessageBoxImage icon = MessageBoxImage.Stop;

        MessageBoxResult result = MessageBox.Show(msg, title, buttons, icon);


        // If they don't, prevent both the session from ending and the

        // application from shutting down

        e.Cancel = (result == MessageBoxResult.No);

    }

}



SessionEnding 이벤트 핸들러에게 전달된 SessionEndingCancelEventArgs 파라미터는 ReasonSessionEnding 속성을 통해 세션 종료의 원인을 노출하고, 세션 종료를 취소할 수 있는 Cancel 속성을 구현합니다.

종료(Exit)
애플리케이션에 의해 - 처리되지 않은 예외나 사용자 세션 종료에 의한 종료가 아닌 - 종료(shutdown)가 시작되었다면 애플리케이션의 라이프타임은 끝이 날 것입니다. 종료하기 전, 애플리케이션은 애플리케이션의 상태를 보관하는 것과 같은 최종 처리 동작을 필요로 할 것입니다. 이 경우, Exit 이벤트를 처리할 수 있습니다.

XAML
<Application
    xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
    xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
    x:Class="App"
    StartupUri="MainWindow.xaml"
    Startup="App_Startup"
    Exit="App_Exit" />


C#

using System;

using System.Windows;

using System.IO;

using System.IO.IsolatedStorage;

public partial class App : Application

{

    string filename = "App.txt";

    void App_Exit(object sender, ExitEventArgs e)

    {

        // Persist application-scope property to isolated storage

        IsolatedStorageFile storage = IsolatedStorageFile.GetUserStoreForDomain();

        using (IsolatedStorageFileStream stream = new IsolatedStorageFileStream(filename, FileMode.Create, storage))

        using (StreamWriter writer = new StreamWriter(stream))

        {

            // Persist each application-scope property individually

            foreach (string key in this.Properties.Keys)

            {

                writer.WriteLine("{0},{1}", key, this.Properties[key]);

            }

        }

    }

}


종료 코드(Exit Code)
애플리케이션은 사용자 요청에 응답한 OS에 의해 가장 많이 시작됩니다. 그러나, 애플리케이션은 어떤 특정한 작업을 수행하기 위하여 다른 애플리케이션으로부터 시작될 수 있습니다. 이 경우, 호출하는 쪽과 호출받은 애플리케이션은 분리된 프로세스에서 동작합니다. 이런 상황에서 호출한 애플리케이션의 실행은 호출받은 애플리케이션이 어떻게 종료되었냐에 달려있습니다. 이 상황에서, 호출받은 애플리케이션은 exit code로 알려진 특수한 정수 코드를 사용함으로서 어떻게 종료되었는지를 알리는 값을 반환할 수 있습니다. 기본적으로, Application0의 값을 반환할 것입니다. 이 값을 변경하기 위해, exit code가 될 정수 매개 변수를 받아들이도록 오버로드된 Shutdown을 호출할 수 있습니다.

C#
// Shutdown and return a custom exit code
Application.Current.Shutdown(-1);


Exit 이벤트를 처리하여 exit code의 값을 검출하고 변경할 수 있습니다. Exit 이벤트 핸들러는 ApplicationExitCode 속성으로 exit code에의 접근을 제공하는 ExitEventArgs를 전달합니다. 자세한 정보는 Exit를 참고합니다.

애플리케이션 라이프타임 이벤트
다음 그림은 애플리케이션의 라이프타임에서 중요한 이벤트와 그것이 발생하는 순서를 표현합니다.
사용자 삽입 이미지

다른 애플리케이션 서비스

이 토픽은 Application에 의해 나타나는 애플리케이션의 핵심 라이프타임을 다룹니다. 그러나, 애플리케이션은 다음을 포함하는 더욱 자세하게 논의될 또 다른 서비스를 제공합니다.
  • 애플리케이션과 윈도 관리.
  • 애플리케이션-스코프 속성.
  • 애플리케이션-스코프 리소스.
  • 애플리케이션과 내비게이션 관리.

애플리케이션과 윈도
ApplicationWindow는 가까운 관계에 있습니다. 앞서 살펴본 것처럼, 애플리케이션의 라이프타임은 ShutdownMode 속성으로 지정되는 윈도의 라이프타임에 달려있다고 할 수 있습니다. 애플리케이션은 어떤 윈도가 메인 애플리케이션 윈도(System.Windows.Application.MainWindow)로 지정되었는지 기록하고, 현재 인스턴스화 된 윈도(System.Windows.Application.Windows)의 목록을 관리합니다.

더욱 자세한 정보는 WPF Windows Overview를 참고합니다.

애플리케이션 스코프 속성
애플리케이션은 애플리케이션 영역을 넘어 공유할 수 있는 상태를 노출하기 위한 Properties 속성을 구현합니다. 다음은 Properties를 사용하는 예제를 제공합니다.

C#
  // Set an application-scope property with a custom type
  CustomType customType = new CustomType();
  Application.Current.Properties["CustomType"] = customType;
...
  // Get an application-scope property
  // NOTE: Need to convert since Application.Properties is a dictionary of System.Object
  CustomType customType = (CustomType)Application.Current.Properties["CustomType"];

자세한 정보는 다음을 참고합니다.

애플리케이션-스코프 리소스
애플리케이션은 개발자가 애플리케이션간 유저 인터페이스(UI) 리소스를 공유할 수 있게 하는 Resources 속성을 구현합니다. 다음은 Resources(※역주 : 원문에는 Properties라고 되어 있지만, 오류라고 생각됩니다.)를 사용하는 예제를 제공합니다.

C#
  // Set an application-scope resource
  Application.Current.Resources["ApplicationScopeResource"] = Brushes.White;
...
  // Get an application-scope resource Brush whiteBrush = (Brush)Application.Current.Resources["ApplicationScopeResource"];

자세한 정보는 다음을 참고합니다.

애플리케이션과 내비게이션
내비게이션을 가진 독립적인 애플리케이션을 위해, NavigationWindow과 Frame이나 Application이 검출하는 애플리케이션내의 내비게이션과 다음과 같은 적절한 이벤트를 사용합니다.

자세한 정보는 Navigation Overview를 참고합니다.

애플리케이션과 애플리케이션 데이터 파일
WPF 애플리케이션은 리소스 데이터 파일, 컨텐트 데이터 파일 및 원격 데이터 파일을 포함한 몇 가지 데이터 파일의 종류를 관리할 수 있습니다. 다음 헬퍼 메소드는 이 데이터 파일의 종류를 로드하는데 사용할 수 있습니다.

참고

레퍼런스
Application
컨셉
WPF Windows Overview
Navigation Overview
WPF Data Files

신고
Posted by gongdo


티스토리 툴바