WPF-Anwendungsressource, Inhalts- und Datendateien

Microsoft Windows-Anwendungen hängen oftmals von Dateien ab, die nicht ausführbare Daten enthalten, wie etwa XAML (Extensible Application Markup Language), Bilder, Video und Audio. WPF (Windows Presentation Foundation) bietet spezielle Unterstützung zum Konfigurieren, Identifizieren und Verwenden dieser Arten von Datendatei, die als Anwendungsdatendateien bezeichnet werden. Diese Unterstützung bezieht sich auf einen bestimmten Satz von Anwendungsdatendateitypen, einschließlich:

  • Ressourcendateien: Datendateien, die entweder in eine ausführbare oder in eine WPF-Bibliotheksassembly kompiliert werden.

  • Inhaltsdateien: Eigenständige Datendateien, die einer ausführbaren WPF-Assembly explizit zugeordnet sind.

  • Dateien der Ursprungssite: Eigenständige Datendateien, die keiner ausführbaren WPF-Assembly zugeordnet sind.

Ein wichtiger Unterschied zwischen diesen drei Dateitypen besteht darin, dass die Ressourcen- und Inhaltsdateien zur Buildzeit bekannt sind. Sie sind einer Assembly explizit bekannt. Dateien der Ursprungssite sind einer Assembly u. U. überhaupt nicht oder lediglich implizit über den Verweis auf einen Paket-URI (Uniform Resource Identifier) bekannt. Im letzteren Fall kann nicht garantiert werden, dass die Datei der Ursprungssite, auf die verwiesen wird, tatsächlich vorhanden ist.

Für den Verweis auf Anwendungsdatendateien verwendet WPF (Windows Presentation Foundation) das Paket-URI-Schema (Uniform Resource Identifier), das detailliert unter Paket-URI in WPF beschrieben ist.

In diesem Thema wird beschrieben, wie Sie Anwendungsdatendateien konfigurieren und verwenden.

Ressourcendateien

Wenn eine Anwendungsdatendatei einer Anwendung stets zur Verfügung stehen muss, kann die Verfügbarkeit nur dadurch gewährleistet werden, dass die Datei in eine der ausführbaren Hauptassemblys einer Anwendung oder in eine der Assemblys kompiliert wird, auf die verwiesen wird. Dieser Typ von Anwendungsdatendatei wird als Ressourcendatei bezeichnet.

Verwenden Sie die Ressourcendateien in folgenden Fällen:

  • Sie müssen den Inhalt der Ressourcendatei nicht aktualisieren, nachdem sie in eine Assembly kompiliert wurde.

  • Sie möchten die Komplexität der Anwendungsverteilung vereinfachen, indem Sie die Anzahl von Dateiabhängigkeiten verringern.

  • Die Anwendungsdatendatei muss lokalisierbar sein (siehe Übersicht über WPF-Globalisierung und -Lokalisierung).

Hinweis

Die Ressourcendateien, die in diesem Abschnitt beschrieben werden, sind anders als die Ressourcendateien, die in XAML-Ressourcen beschrieben werden und anders als die eingebetteten oder verknüpften Ressourcen, die in Verwalten von Anwendungsressourcen (.NET) beschrieben werden.

Konfigurieren von Ressourcendateien

In WPF ist eine Ressourcendatei eine Datei, die in einem MSBuild-Projekt (Microsoft-Build-Engine) als Resource-Element enthalten ist.

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

Hinweis

In Visual Studio erstellen Sie eine Ressourcendatei, indem Sie einem Projekt eine Datei hinzufügen und seine Build Action auf Resource festlegen.

Wenn das Projekt erstellt wird, kompiliert MSBuild die Ressource in die Assembly.

Verwenden von Ressourcendateien

Zum Laden einer Ressourcendatei können Sie die GetResourceStream-Methode der Application-Klasse aufrufen und einen Paket-URI zur Identifizierung der gewünschten Ressourcendatei übergeben. GetResourceStream gibt ein StreamResourceInfo-Objekt zurück, das die Ressourcendatei als Stream verfügbar macht und ihren Inhaltstyp beschreibt.

Beispielhaft wird im folgenden Code gezeigt, wie Sie GetResourceStream verwenden, um eine Page-Ressourcendatei zu laden und als Inhalt eines Frame (pageFrame) festzulegen:

// 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

Der Aufruf von GetResourceStream gibt Ihnen zwar Zugriff auf den Stream, Sie müssen jedoch die zusätzliche Arbeit ausführen, ihn in den Typ Eigenschaft zu konvertieren, mit dem Sie ihn festlegen. Stattdessen können Sie WPF das Öffnen und Konvertieren des Stream übertragen, indem Sie eine Ressourcendatei mithilfe von Code direkt in die Eigenschaft eines Typs laden.

Im folgenden Beispiel wird gezeigt, wie eine Page mithilfe von Code direkt in einen Frame (pageFrame) geladen wird.

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

Das folgende Beispiel entspricht dem Markup des vorangehenden Beispiels.

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

Anwendungscodedateien als Ressourcendateien

Auf einen speziellen Satz von WPF-Anwendungscodedateien kann mithilfe von Paket-URIs verwiesen werden, einschließlich Fenstern, Seiten, Flussdokumenten und Ressourcenverzeichnissen. Sie können beispielsweise die Application.StartupUri-Eigenschaft mit einem Paket-URI festlegen, der auf das Fenster oder die Seite verweist, das bzw. die beim Starten einer Anwendung geladen werden soll.

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

Diese Vorgehensweise bietet sich an, wenn eine XAML-Datei als Page-Element in ein MSBuild-Projekt eingefügt wird.

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

Hinweis

In Visual Studio fügen Sie einem Projekt ein neues Window, NavigationWindow, Page, FlowDocument oder ResourceDictionary hinzu, das Build Action für die Markupdatei ist standardmäßig auf Page festgelegt.

Wenn ein Projekt mit Page-Elementen kompiliert wird, werden die XAML-Elemente in das Binärformat konvertiert und in die zugeordnete Assembly kompiliert. Folglich können diese Dateien auf die gleiche Weise verwendet werden wie typische Ressourcendateien.

Hinweis

Wenn eine XAML-Datei als ein Resource-Element konfiguriert wird und nicht über eine CodeBehind-Datei verfügt, werden die XAML-Rohdaten in eine Assembly anstelle einer Binärversion der XAML-Rohdaten kompiliert.

Inhaltsdateien

Eine Inhaltsdatei wird zusammen mit einer ausführbaren Assembly als Loose-Datei verteilt. Obwohl Assemblys nicht in eine Assembly kompiliert werden, werden sie mit Metadaten kompiliert, die eine Zuordnung mit den einzelnen Inhaltsdateien herstellen.

Verwenden Sie Inhaltsdateien, wenn die Anwendung einen speziellen Satz von Anwendungsdatendateien erfordert, die aktualisierbar sein soll, ohne dass die Assembly, die sie verwendet, neu kompiliert werden muss.

Konfigurieren von Inhaltsdateien

Zum Hinzufügen einer Inhaltsdatei zu einem Projekt muss eine Anwendungsdatendatei als Content-Element enthalten sein. Da eine Inhaltsdatei nicht direkt in die Assembly kompiliert wird, müssen Sie außerdem das CopyToOutputDirectory-Metadatenelement von MSBuild festlegen, um anzugeben, dass die Inhaltsdatei an einen Ort kopiert wird, der relativ zur erstellten Assembly ist. Wenn die Ressource bei jedem Erstellen eines Projekts in den Buildausgabeordner kopiert werden soll, legen Sie das CopyToOutputDirectory-Metadatenelement auf den Wert Always fest. Andernfalls können Sie mithilfe des Werts PreserveNewest sicherstellen, dass lediglich die neueste Version der Ressource in den Buildausgabeordner kopiert wird.

Im Folgenden wird eine Datei gezeigt, die als Inhaltsdatei konfiguriert ist und nur dann in den Buildausgabeordner kopiert wird, wenn dem Projekt eine neue Version der Ressource hinzugefügt wird.

<Project xmlns="http://schemas.microsoft.com/developer/msbuild/2003" ... >  
  ...  
  <ItemGroup>  
    <Content Include="ContentFile.xaml">  
      <CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>  
    </Content>  
  </ItemGroup>  
  ...  
</Project>  

Hinweis

In Visual Studio erstellen Sie eine Inhaltsdatei, indem Sie einem Projekt eine Datei hinzufügen und seine Build Action auf Content sowie seine Copy to Output Directory auf Copy always (gleichbedeutend mit Always) und Copy if newer (gleichbedeutend mit PreserveNewest) festlegen.

Beim Erstellen des Projekts wird für jede Inhaltsdatei ein AssemblyAssociatedContentFileAttribute-Attribut in die Metadaten der Assembly kompiliert.

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

Der Wert von AssemblyAssociatedContentFileAttribute impliziert den Pfad zur Inhaltsdatei relativ zu ihrer Position im Projekt. Wenn sich eine Inhaltsdatei beispielsweise in einem Projektunterordner befand, werden die zusätzlichen Pfadinformationen in den Wert von AssemblyAssociatedContentFileAttribute einbezogen.

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

Der Wert von AssemblyAssociatedContentFileAttribute ist zugleich der Wert des Pfads zur Inhaltsdatei im Buildausgabeordner.

Verwenden von Inhaltsdateien

Zum Laden einer Inhaltsdatei können Sie die GetContentStream-Methode der Application-Klasse aufrufen und einen Paket-URI zur Identifizierung der gewünschten Inhaltsdatei übergeben. GetContentStream gibt ein StreamResourceInfo-Objekt zurück, das die Inhaltsdatei als Stream verfügbar macht und ihren Inhaltstyp beschreibt.

Beispielhaft wird im folgenden Code gezeigt, wie Sie GetContentStream verwenden, um eine Page-Inhaltsdatei zu laden und als Inhalt eines Frame (pageFrame) festzulegen.

// 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

Der Aufruf von GetContentStream gibt Ihnen zwar Zugriff auf den Stream, Sie müssen jedoch die zusätzliche Arbeit ausführen, ihn in den Typ Eigenschaft zu konvertieren, mit dem Sie ihn festlegen. Stattdessen können Sie WPF das Öffnen und Konvertieren des Stream übertragen, indem Sie eine Ressourcendatei mithilfe von Code direkt in die Eigenschaft eines Typs laden.

Im folgenden Beispiel wird gezeigt, wie eine Page mithilfe von Code direkt in einen Frame (pageFrame) geladen wird.

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

Das folgende Beispiel entspricht dem Markup des vorangehenden Beispiels.

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

Dateien der Ursprungssite

Ressourcendateien sind durch eine explizite Beziehung an die Assemblys gebunden, mit denen sie gemäß dem AssemblyAssociatedContentFileAttribute verteilt wurden. Es kann jedoch vorkommen, dass Sie eine implizite oder nicht vorhandene Beziehung zwischen einer Assembly und einer Anwendungsdatendatei herstellen, u. a. in folgenden Fällen:

  • Eine Datei ist zur Kompilierzeit nicht vorhanden.

  • Sie wissen bis zur Laufzeit nicht, welche Dateien von der Assembly benötigt werden.

  • Sie möchten in der Lage sein, Dateien ohne Neukompilierung der Assembly, der sie zugeordnet sind, zu aktualisieren.

  • Die Anwendung verwendet große Datendateien, z. B. Audio und Video. Diese sollen von Benutzern nur heruntergeladen werden, wenn sie dies wünschen.

Diese Dateitypen lassen sich mithilfe der herkömmlichen URI-Schemas herunterladen, z. B. den Schemas file:/// und http://.

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

Die Schemas file:/// und http:// setzen jedoch volle Vertrauenswürdigkeit der Anwendung voraus. Wenn die Anwendung eine XAML-Browseranwendung (XBAP) ist und vom Internet oder Intranet aus gestartet wurde und nur diejenigen Berechtigungen anfordert, die für Anwendungen gewährt werden, die von diesen Orten aus gestartet werden, können Loose-Dateien nur von der Ursprungssite der Anwendung (Startspeicherort) aus geladen werden. Solche Dateien werden als Dateien der Ursprungssite bezeichnet.

Dateien der Ursprungssite stellen für teilweise vertrauenswürdige Anwendungen die einzige Option dar, obwohl sie nicht auf letztere beschränkt sind. Anwendungen mit voller Vertrauenswürdigkeit müssen ggf. Anwendungsdatendateien laden, die sie zur Buildzeit nicht kennen. Obwohl Anwendungen mit voller Vertrauenswürdigkeit „file:///“ verwenden könnten, ist anzunehmen, dass die Anwendungsdatendateien im selben Ordner oder in einem Unterordner der Anwendungsassembly installiert werden. In einem solchen Fall gestaltet sich die Verwendung des Verweises auf die Ursprungssite einfacher als die Verwendung von „file:///“, da die Verwendung von „file:///“ von Ihnen erfordert, den vollständigen Pfad zur Datei auszuarbeiten.

Hinweis

Dateien der Ursprungssite werden nicht mit einer XAML-Browseranwendung (XBAP) auf einem Clientcomputer zwischengespeichert, Inhaltsdateien dagegen schon. Folglich werden sie nur heruntergeladen, wenn sie ausdrücklich angefordert werden. Wenn eine XAML-Browseranwendung (XBAP) große Mediendateien enthält, führt die Konfiguration dieser Dateien als Dateien der Ursprungssite zu einem erheblich schnelleren Start der Originalanwendung. Außerdem werden die Dateien nur auf Anforderung heruntergeladen.

Konfigurieren der Dateien der Ursprungssite

Wenn die Dateien der Ursprungssite zur Kompilierungszeit nicht vorhanden oder unbekannt sind, müssen Sie die herkömmlichen Bereitstellungsmechanismen verwenden, um zu gewährleisten, dass die angeforderten Dateien zur Laufzeit verfügbar sind, einschließlich des XCopy-Befehlszeilenprogramms oder des Microsoft Windows Installers.

Wenn Sie die Dateien, die auf der Ursprungssite gespeichert werden sollen, zur Kompilierungszeit kennen, aber dennoch explizite Abhängigkeit vermeiden möchten, können Sie diese Dateien einem MSBuild-Projekt als None-Element hinzufügen. Wie bei Inhaltsdateien müssen Sie das CopyToOutputDirectory-Attribut von MSBuild festlegen, um anzugeben, dass die Datei der Ursprungssite an einen Speicherort kopiert wird, der relativ zur erstellten Assembly ist. Dabei wird entweder der Always-Wert oder der PreserveNewest-Wert angegeben.

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

Hinweis

In Visual Studio erstellen Sie eine Datei der Ursprungssite, indem Sie einem Projekt eine Datei hinzufügen und seine Build Action auf None festlegen.

Beim Erstellen des Projekts kopiert MSBuild die angegebenen Dateien in den Buildausgabeordner.

Verwenden der Dateien der Ursprungssite

Zum Laden einer Datei der Ursprungssite können Sie die GetRemoteStream-Methode der Application-Klasse aufrufen und einen Paket-URI zur Identifizierung der gewünschten Datei der Ursprungssite übergeben. GetRemoteStream gibt ein StreamResourceInfo-Objekt zurück, das die Datei der Ursprungssite als Stream verfügbar macht und ihren Inhaltstyp beschreibt.

Beispielhaft wird im folgenden Code gezeigt, wie Sie GetRemoteStream verwenden, um eine Page-Datei der Ursprungssite zu laden und als Inhalt eines Frame (pageFrame) festzulegen.

// 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

Der Aufruf von GetRemoteStream gibt Ihnen zwar Zugriff auf den Stream, Sie müssen jedoch die zusätzliche Arbeit ausführen, ihn in den Typ Eigenschaft zu konvertieren, mit dem Sie ihn festlegen. Stattdessen können Sie WPF das Öffnen und Konvertieren des Stream übertragen, indem Sie eine Ressourcendatei mithilfe von Code direkt in die Eigenschaft eines Typs laden.

Im folgenden Beispiel wird gezeigt, wie eine Page mithilfe von Code direkt in einen Frame (pageFrame) geladen wird.

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

Das folgende Beispiel entspricht dem Markup des vorangehenden Beispiels.

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

Neuerstellung nach Ändern des Buildtyps

Nachdem Sie den Buildtyp einer Anwendungsdatendatei geändert haben, müssen Sie die gesamte Anwendung neu erstellen, um zu gewährleisten, dass diese Änderungen übernommen werden. Wenn Sie nur die Anwendung erstellen, werden die Änderungen nicht übernommen.

Siehe auch