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


티스토리 툴바