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


티스토리 툴바