WPF 애플리케이션 리소스, 콘텐츠 및 데이터 파일

Microsoft Windows 애플리케이션은 XAML(Extensible Application Markup Language), 이미지, 비디오 및 오디오와 같이 실행할 수 없는 데이터가 포함된 파일에 의존하는 경우가 있습니다. WPF(Windows Presentation Foundation)에서는 애플리케이션 데이터 파일이라고 하는 이러한 유형의 데이터 파일을 구성하고, 식별하고, 사용할 수 있도록 하는 특별한 지원을 제공합니다. 이러한 지원에는 다음을 포함한 특정 애플리케이션 데이터 파일 형식 집합이 포함됩니다.

  • 리소스 파일: 실행 가능 또는 라이브러리 WPF 어셈블리로 컴파일되는 데이터 파일.

  • 콘텐츠 파일: 실행 가능 WPF 어셈블리와 명시적으로 연결된 독립형 데이터 파일.

  • 원본 사이트 파일: 실행 가능 WPF 어셈블리와 연결되지 않은 독립형 데이터 파일.

이 세 가지 파일 형식을 구분하는 한 가지 중요한 차이점은 리소스 파일과 콘텐츠 파일은 빌드할 때 인식된다는 점입니다. 어셈블리는 명시적으로 이 파일을 인식합니다. 하지만 원본 사이트 파일의 경우에는 어셈블리가 이를 전혀 인식하지 못하거나 Pack URI(Uniform Resource Identifier) 참조를 통해 암시적으로 인식합니다. 후자의 경우 참조되는 원본 사이트 파일이 실제로 존재한다는 보장은 없습니다.

애플리케이션 데이터 파일을 참조하기 위해 WPF(Windows Presentation Foundation)는 Pack URI(Uniform Resource Identifier) 체계를 사용합니다. 이 체계에 대해서는 WPF의 Pack URI에서 자세히 설명합니다.

이 항목에서는 애플리케이션 데이터 파일을 구성하고 사용하는 방법을 설명합니다.

리소스 파일

애플리케이션에서 애플리케이션 데이터 파일을 항상 사용할 수 있어야 하는 경우 가용성을 보장하는 유일한 방법은 데이터 파일을 애플리케이션의 주 실행 어셈블리 또는 참조되는 어셈블리 중 하나로 컴파일하는 것입니다. 이러한 형식의 애플리케이션 데이터 파일을 리소스 파일이라고 합니다.

다음과 같은 경우에 리소스 파일을 사용해야 합니다.

  • 어셈블리로 컴파일한 뒤에는 리소스 파일의 콘텐츠를 업데이트할 필요가 없는 경우.

  • 파일 종속성의 수를 줄여 애플리케이션 배포의 복잡성을 줄이려는 경우.

  • 애플리케이션 데이터 파일을 지역화할 수 있어야 합니다(WPF 전역화 및 지역화 개요 참조).

참고

이 섹션에서 설명하는 리소스 파일은 XAML 리소스에 설명된 리소스 파일과 다르고, 애플리케이션 리소스 관리(.NET)에 설명되어 있는 포함된 리소스 또는 링크된 리소스와 다릅니다.

리소스 파일 구성

WPF에서 리소스 파일은 Microsoft 빌드 엔진(MSBuild) 프로젝트에 Resource 항목으로 포함된 파일입니다.

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

참고

Visual Studio에서 프로젝트에 파일을 추가하고 해당 Build ActionResource로 설정하여 리소스 파일을 만듭니다.

프로젝트를 빌드할 때 MSBuild에서 리소스를 어셈블리로 컴파일합니다.

리소스 파일 사용

리소스 파일을 로드하려면 Application 클래스의 GetResourceStream 메서드를 호출하여 원하는 리소스 파일을 식별하는 팩 URI를 전달할 수 있습니다. GetResourceStream은 리소스 파일을 Stream으로 노출하고 해당 콘텐츠 형식을 설명하는 StreamResourceInfo 개체를 반환합니다.

예를 들어 다음 코드에서는 GetResourceStream을 사용하여 Page 리소스 파일을 로드하고 이를 Frame(pageFrame)의 콘텐츠로 설정하는 방법을 보여냅니다.

// 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;
' Navigate to xaml page
Dim uri As New Uri("/PageResourceFile.xaml", UriKind.Relative)
Dim info As StreamResourceInfo = Application.GetResourceStream(uri)
Dim reader As New System.Windows.Markup.XamlReader()
Dim page As Page = CType(reader.LoadAsync(info.Stream), Page)
Me.pageFrame.Content = page

GetResourceStream을 호출하면 Stream에 액세스할 수 있지만 이를 설정하는 데 사용할 속성의 형식으로 변환하는 작업을 추가적으로 수행해야 합니다. 대신 코드를 사용해 리소스 파일을 해당 형식의 속성으로 직접 로드하여 WPF에서 Stream 열기와 변환을 처리하도록 할 수 있습니다.

다음 예제에서는 코드를 사용하여 PageFrame(pageFrame)에 직접 로드하는 방법을 보여줍니다.

Uri pageUri = new Uri("/PageResourceFile.xaml", UriKind.Relative);
this.pageFrame.Source = pageUri;
Dim pageUri As New Uri("/PageResourceFile.xaml", UriKind.Relative)
Me.pageFrame.Source = pageUri

다음 예제는 태그를 사용하여 앞의 예제를 구현한 것입니다.

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

리소스 파일로 사용되는 애플리케이션 코드 파일

창, 페이지, 유동 문서 및 리소스 사전을 비롯한 팩 URI를 사용하여 특별한 WPF 애플리케이션 코드 파일 세트를 참조할 수 있습니다. 예를 들어 애플리케이션이 시작될 때 로드할 창이나 페이지를 참조하는 팩 URI로 Application.StartupUri 속성을 설정할 수 있습니다.

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

XAML 파일이 MSBuild 프로젝트에 Page 항목으로 포함되는 경우 이 작업을 수행할 수 있습니다.

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

참고

Visual Studio에서 새 Window, NavigationWindow, Page, FlowDocument 또는 ResourceDictionary를 프로젝트에 추가하면 태그 파일의 Build Action이 기본적으로 Page로 설정됩니다.

Page 항목이 있는 프로젝트가 컴파일될 때 XAML 항목은 이진 형식으로 변환되고 연결된 어셈블리로 컴파일됩니다. 결과적으로 이 파일을 일반적인 리소스 파일과 같은 방법으로 사용할 수 있습니다.

참고

XAML 파일이 Resource 항목으로 구성되고, 코드 숨김 파일이 없는 경우 원시 XAML은 원시 XAML의 이진 버전이 아니라 어셈블리로 컴파일됩니다.

콘텐츠 파일

콘텐츠 파일은 실행 가능한 어셈블리와 함께 느슨한 파일로 배포됩니다. 어셈블리로 컴파일되지는 않지만 어셈블리는 각 콘텐츠 파일과 연결되는 메타데이터와 함께 컴파일됩니다.

데이터 파일을 사용하는 어셈블리를 재컴파일하지 않고 업데이트하고자 하는 애플리케이션 데이터 파일을 애플리케이션에서 필요로 할 때는 콘텐츠 파일을 사용해야 합니다.

콘텐츠 파일 구성

프로젝트에 콘텐츠 파일을 추가하려면 애플리케이션 데이터 파일이 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>  

참고

Visual Studio에서는 파일을 프로젝트에 추가하고 해당 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 메서드를 호출하여 원하는 콘텐츠 파일을 식별하는 팩 URI를 전달할 수 있습니다. GetContentStream은 콘텐츠 파일을 Stream으로 노출하고 해당 콘텐츠 형식을 설명하는 StreamResourceInfo 개체를 반환합니다.

예를 들어 다음 코드에서는 GetContentStream을 사용하여 Page 콘텐츠 파일을 로드하고 이를 Frame(pageFrame)의 콘텐츠로 설정하는 방법을 보여냅니다.

// 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;
' Navigate to xaml page
Dim uri As New Uri("/PageContentFile.xaml", UriKind.Relative)
Dim info As StreamResourceInfo = Application.GetContentStream(uri)
Dim reader As New System.Windows.Markup.XamlReader()
Dim page As Page = CType(reader.LoadAsync(info.Stream), Page)
Me.pageFrame.Content = page

GetContentStream을 호출하면 Stream에 액세스할 수 있지만 이를 설정하는 데 사용할 속성의 형식으로 변환하는 작업을 추가적으로 수행해야 합니다. 대신 코드를 사용해 리소스 파일을 해당 형식의 속성으로 직접 로드하여 WPF에서 Stream 열기와 변환을 처리하도록 할 수 있습니다.

다음 예제에서는 코드를 사용하여 PageFrame(pageFrame)에 직접 로드하는 방법을 보여줍니다.

Uri pageUri = new Uri("/PageContentFile.xaml", UriKind.Relative);
this.pageFrame.Source = pageUri;
Dim pageUri As New Uri("/PageContentFile.xaml", UriKind.Relative)
Me.pageFrame.Source = pageUri

다음 예제는 태그를 사용하여 앞의 예제를 구현한 것입니다.

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

원본 사이트 파일

리소스 파일은 AssemblyAssociatedContentFileAttribute에 의해 정의된 것처럼 함께 배포되는 어셈블리와 명시적인 관계를 가집니다. 하지만 다음과 같이 어셈블리와 애플리케이션 데이터 파일 사이에 암시적 관계 또는 존재하지 않는 관계를 설정해야 할 경우가 종종 있습니다.

  • 컴파일 시 파일이 존재하지 않습니다.

  • 런타임까지 어셈블리에 필요한 파일을 모르는 경우.

  • 연결된 어셈블리를 재컴파일하지 않고 파일을 업데이트할 수 있어야 하는 경우.

  • 애플리케이션에서 오디오나 비디오와 같은 대용량 데이터 파일을 사용하며 사용자가 필요할 때에만 이를 다운로드하도록 하려는 경우.

file:///http:// 스키마와 같은 기존의 URI 스키마를 사용하여 이러한 형식의 파일을 로드할 수 있습니다.

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

하지만 file:///http:// 스키마를 사용하려면 애플리케이션이 완전히 신뢰되어야 합니다. 애플리케이션이 인터넷이나 인트라넷에서 시작된 XBAP(XAML 브라우저 애플리케이션)이며 해당 위치에서 시작된 애플리케이션에 허용되는 권한 집합만 필요로 하는 경우에 느슨한 파일만 애플리케이션의 원본 사이트(시작 위치)에서 로드할 수 있습니다. 이러한 파일을 원본 사이트 파일이라고 합니다.

원본 사이트 파일이 부분 신뢰 애플리케이션에서만 사용되는 것은 아니지만 부분 신뢰 애플리케이션에서는 원본 사이트 파일만을 사용할 수 있습니다. 완전 신뢰 애플리케이션의 경우에서도 빌드할 때 인식하지 못한 애플리케이션 데이터 파일을 로드해야 할 경우가 있습니다. 완전 신뢰 애플리케이션은 file:///을 사용할 수 있지만 이 경우 애플리케이션 데이터 파일이 애플리케이션 어셈블리와 같은 폴더 또는 하위 폴더에 설치될 수 있습니다. file:///에는 파일의 전체 경로를 사용해야 하기 때문에 file:///을 사용하는 방법보다 원본 사이트 참조를 사용하는 방법이 쉽습니다.

참고

콘텐츠 파일은 클라이언트 컴퓨터에서 XBAP(XAML 브라우저 애플리케이션)로 캐시되지만 원본 사이트 파일은 캐시되지 않습니다. 따라서 구체적으로 요청된 경우에만 다운로드됩니다. XBAP(XAML 브라우저 애플리케이션) 애플리케이션에 용량이 큰 미디어 파일이 있는 경우 이를 원본 사이트 파일로 구성하면 애플리케이션을 처음 시작할 때의 속도가 훨씬 빨라지고 필요로 할 때만 파일이 다운로드됩니다.

원본 사이트 파일 구성

원본 사이트 파일이 없거나 컴파일할 때 인식되지 않는 경우 XCopy 명령줄 프로그램 또는 Microsoft Windows Installer 사용을 포함하여 기존 배포 메커니즘을 사용하여 필요한 파일을 런타임에 사용할 수 있도록 해야 합니다.

컴파일할 때 원본 사이트에서 찾아야 할 파일을 알고 있지만 명시적 종속성을 피하려는 경우에는 해당 파일을 MSBuild 프로젝트에 None 항목으로 추가할 수 있습니다. 이 경우에도 콘텐츠 파일과 마찬가지로 MSBuild CopyToOutputDirectory 특성을 설정하고 Always 값 또는 PreserveNewest 값을 지정하여 원본 사이트 파일이 빌드된 어셈블리에 상대적인 위치로 복사되도록 지정해야 합니다.

<Project xmlns="http://schemas.microsoft.com/developer/msbuild/2003" ... >  
  ...  
  <None Include="PageSiteOfOriginFile.xaml">  
    <CopyToOutputDirectory>Always</CopyToOutputDirectory>  
  </None>  
  ...  
</Project>  

참고

Visual Studio에서는 파일을 프로젝트에 추가하고 Build ActionNone으로 설정하여 원본 사이트 파일을 만듭니다.

프로젝트를 빌드할 때 MSBuild에서 지정된 파일을 빌드 출력 폴더로 복사합니다.

원본 사이트 파일 사용

원본 사이트 파일을 로드하려면 Application 클래스의 GetRemoteStream 메서드를 호출하여 원하는 원본 사이트 파일을 식별하는 팩 URI를 전달할 수 있습니다. GetRemoteStream은 원본 사이트 파일을 Stream으로 노출하고 해당 콘텐츠 형식을 설명하는 StreamResourceInfo 개체를 반환합니다.

예를 들어 다음 코드에서는 GetRemoteStream을 사용하여 Page 원본 사이트 파일을 로드하고 이를 Frame(pageFrame)의 콘텐츠로 설정하는 방법을 보여냅니다.

// 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;
' Navigate to xaml page
Dim uri As New Uri("/SiteOfOriginFile.xaml", UriKind.Relative)
Dim info As StreamResourceInfo = Application.GetRemoteStream(uri)
Dim reader As New System.Windows.Markup.XamlReader()
Dim page As Page = CType(reader.LoadAsync(info.Stream), Page)
Me.pageFrame.Content = page

GetRemoteStream을 호출하면 Stream에 액세스할 수 있지만 이를 설정하는 데 사용할 속성의 형식으로 변환하는 작업을 추가적으로 수행해야 합니다. 대신 코드를 사용해 리소스 파일을 해당 형식의 속성으로 직접 로드하여 WPF에서 Stream 열기와 변환을 처리하도록 할 수 있습니다.

다음 예제에서는 코드를 사용하여 PageFrame(pageFrame)에 직접 로드하는 방법을 보여줍니다.

Uri pageUri = new Uri("pack://siteoforigin:,,,/SiteOfOriginFile.xaml", UriKind.Absolute);
this.pageFrame.Source = pageUri;
Dim pageUri As New Uri("pack://siteoforigin:,,,/Subfolder/SiteOfOriginFile.xaml", UriKind.Absolute)
Me.pageFrame.Source = pageUri

다음 예제는 태그를 사용하여 앞의 예제를 구현한 것입니다.

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

빌드 형식 변경 후 다시 빌드

애플리케이션 데이터 파일의 빌드 형식을 변경한 뒤에는 변경 내용이 적용되도록 전체 애플리케이션을 다시 빌드해야 합니다. 애플리케이션만 빌드하면 변경 내용이 적용되지 않습니다.

참조