Zasób aplikacji WPF, zawartość i pliki danych
Aplikacje systemu Microsoft Windows często zależą od plików, które zawierają dane nie wykonywalne, takie jak Extensible Application Markup Language (XAML), obrazy, wideo i dźwięk. Program Windows Presentation Foundation (WPF) oferuje specjalną obsługę konfigurowania, identyfikowania i używania tych typów plików danych, które są nazywane plikami danych aplikacji. Ta obsługa koncentruje się wokół określonego zestawu typów plików danych aplikacji, w tym:
Pliki zasobów: pliki danych skompilowane do zestawu wykonywalnego lub biblioteki WPF.
Pliki zawartości: autonomiczne pliki danych, które mają jawne skojarzenie z wykonywalnym zestawem WPF.
lokacji plików pochodzenia: autonomiczne pliki danych, które nie mają skojarzenia z wykonywalnym zestawem WPF.
Jedną z ważnych różnic między tymi trzema typami plików jest to, że pliki zasobów i pliki zawartości są znane w czasie kompilacji; zestaw ma jawną wiedzę na ich temat. Jednak w przypadku plików źródła pochodzenia, zestaw może nie mieć żadnej wiedzy na ich temat lub posiadać niejawne informacje za pośrednictwem odniesienia do identyfikatora URI w pakiecie; w tym drugim przypadku nie ma gwarancji, że przywoływany plik źródła pochodzenia faktycznie istnieje.
Aby odwołać się do plików danych aplikacji, program Windows Presentation Foundation (WPF) używa schematu identyfikatora URI (Pack uniform resource identifier), który został szczegółowo opisany w Pack URIs in WPF).
W tym temacie opisano sposób konfigurowania i używania plików danych aplikacji.
Pliki zasobów
Jeśli plik danych aplikacji musi być zawsze dostępny dla aplikacji, jedynym sposobem zagwarantowania dostępności jest skompilowanie go do głównego zestawu wykonywalnego aplikacji lub jednego z przywoływalnych zestawów. Ten typ pliku danych aplikacji jest znany jako plik zasobów .
Pliki zasobów należy używać w następujących przypadkach:
Nie trzeba aktualizować zawartości pliku zasobu po skompilowaniu go do zestawu.
Chcesz uprościć złożoność dystrybucji aplikacji, zmniejszając liczbę zależności plików.
Plik danych aplikacji musi być lokalizowalny (zobacz Globalizacja i lokalizacja WPF — omówienie).
Notatka
Pliki zasobów opisane w tej sekcji są inne niż pliki zasobów opisane w zasoby XAML i inne niż osadzone lub połączone zasoby opisane w Zarządzanie zasobami aplikacji (.NET).
Konfigurowanie plików zasobów
W przypadku WPF plik zasobów jest plikiem dołączonym do projektu przy użyciu aparatu kompilacji Microsoft (MSBuild) jako element Resource
.
<Project xmlns="http://schemas.microsoft.com/developer/msbuild/2003" ... >
...
<ItemGroup>
<Resource Include="ResourceFile.xaml" />
</ItemGroup>
...
</Project>
Notatka
W programie Visual Studio tworzysz plik zasobów, dodając plik do projektu i ustawiając jego Build Action
na Resource
.
Po skompilowaniu projektu program MSBuild kompiluje zasób do zestawu.
Korzystanie z plików zasobów
Aby załadować plik zasobu, możesz wywołać metodę GetResourceStream klasy Application, przekazując identyfikator URI pakietu identyfikujący żądany plik zasobu. GetResourceStream zwraca obiekt StreamResourceInfo, który uwidacznia plik zasobu jako Stream i opisuje jego typ zawartości.
Na przykład poniższy kod pokazuje, jak za pomocą GetResourceStream załadować plik zasobu Page i ustawić go jako zawartość 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
Podczas wywoływania GetResourceStream uzyskuje się dostęp do Stream, jednak trzeba wykonać dodatkową pracę polegającą na przekonwertowaniu jej na typ właściwości, którą będzie się ustawiać. Zamiast tego można pozwolić WPF na zajęcie się otwieraniem i konwersją Stream poprzez załadowanie pliku zasobu bezpośrednio do właściwości określonego typu za pomocą kodu.
W poniższym przykładzie pokazano, jak załadować Page bezpośrednio do Frame (pageFrame
) przy użyciu kodu.
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
Poniższy przykład jest odpowiednikiem znacznika z poprzedniego przykładu.
<Frame Name="pageFrame" Source="PageResourceFile.xaml" />
Pliki kodu aplikacji jako pliki zasobów
Można odwoływać się do specjalnego zestawu plików kodu aplikacji WPF przy użyciu identyfikatorów URI pakietów, w tym okien, stron, dokumentów przepływu i słowników zasobów. Można na przykład ustawić właściwość Application.StartupUri za pomocą identyfikatora URI pakietu, który odwołuje się do okna lub strony, którą chcesz załadować po uruchomieniu aplikacji.
<Application
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
StartupUri="SOOPage.xaml" />
Można to zrobić, gdy plik XAML jest uwzględniony w projekcie MSBuild jako element Page
.
<Project xmlns="http://schemas.microsoft.com/developer/msbuild/2003" ... >
...
<ItemGroup>
<Page Include="MainWindow.xaml" />
</ItemGroup>
...
</Project>
Notatka
W programie Visual Studio, gdy dodajesz nowy Window, NavigationWindow, Page, FlowDocumentlub ResourceDictionary do projektu, Build Action
pliku znaczników będzie ustawione domyślnie na Page
.
Po skompilowaniu projektu z elementami Page
elementy XAML są konwertowane na format binarny i kompilowane w skojarzonym zestawie. W związku z tym te pliki mogą być używane w taki sam sposób, jak typowe pliki zasobów.
Notatka
Jeśli plik XAML jest skonfigurowany jako element Resource
i nie ma pliku code-behind, pierwotny XAML jest kompilowany do zestawu, a nie w wersji binarnej pierwotnego XAML.
Pliki zawartości
Plik zawartości jest dystrybuowany jako oddzielny plik obok zestawu wykonywalnego. Mimo że nie są one kompilowane w zestawie, zestawy są kompilowane z metadanymi, które ustanawiają skojarzenie z każdym plikiem zawartości.
Pliki zawartości należy używać, gdy aplikacja wymaga określonego zestawu plików danych aplikacji, które można aktualizować bez ponownego kompilowania zestawu, który z nich korzysta.
Konfigurowanie plików zawartości
Aby dodać plik zawartości do projektu, plik danych aplikacji musi zostać dołączony jako element Content
. Ponadto, ponieważ plik zawartości nie jest kompilowany bezpośrednio w zestawie, należy ustawić element metadanych msBuild CopyToOutputDirectory
, aby określić, że plik zawartości jest kopiowany do lokalizacji powiązanej z wbudowanym zestawem. Jeśli chcesz skopiować zasób do folderu wyjściowego kompilacji za każdym razem, gdy projekt zostanie skompilowany, należy ustawić element metadanych CopyToOutputDirectory
z wartością Always
. W przeciwnym razie można upewnić się, że tylko najnowsza wersja zasobu jest kopiowana do folderu wyjściowego kompilacji przy użyciu wartości PreserveNewest
.
Poniżej przedstawiono plik skonfigurowany jako plik zawartości, który jest kopiowany do folderu wyjściowego kompilacji tylko wtedy, gdy do projektu zostanie dodana nowa wersja zasobu.
<Project xmlns="http://schemas.microsoft.com/developer/msbuild/2003" ... >
...
<ItemGroup>
<Content Include="ContentFile.xaml">
<CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
</Content>
</ItemGroup>
...
</Project>
Notatka
W programie Visual Studio tworzysz plik zawartości, dodając plik do projektu i ustawiając jego Build Action
na Content
i ustawiając jego Copy to Output Directory
na Copy always
(taki sam jak Always
) i Copy if newer
(taki sam jak PreserveNewest
).
Po skompilowaniu projektu atrybut AssemblyAssociatedContentFileAttribute jest kompilowany w metadanych zestawu dla każdego pliku zawartości.
[assembly: AssemblyAssociatedContentFile("ContentFile.xaml")]
Wartość AssemblyAssociatedContentFileAttribute oznacza ścieżkę do pliku zawartości względem jego pozycji w projekcie. Jeśli na przykład plik zawartości znajduje się w podfolderze projektu, dodatkowe informacje o ścieżce zostaną włączone do wartości AssemblyAssociatedContentFileAttribute.
[assembly: AssemblyAssociatedContentFile("Resources/ContentFile.xaml")]
Wartość AssemblyAssociatedContentFileAttribute jest również wartością ścieżki do pliku zawartości w folderze wyjściowym kompilacji.
Korzystanie z plików treści
Aby załadować plik zawartości, możesz wywołać metodę GetContentStream klasy Application, przekazując identyfikator URI pakietu identyfikujący żądany plik zawartości. GetContentStream zwraca obiekt StreamResourceInfo, który uwidacznia plik zawartości jako Stream i opisuje jego typ zawartości.
Na przykład poniższy kod pokazuje, jak za pomocą GetContentStream załadować plik zawartości Page i ustawić go jako zawartość 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
Podczas wywoływania GetContentStream uzyskujesz dostęp do Stream, ale musisz wykonać dodatkową pracę, aby przekonwertować go na typ właściwości, z którym go ustawisz. Zamiast tego można zezwolić WPF na otwieranie i konwertowanie Stream przez załadowanie pliku zasobu bezpośrednio do właściwości typu przy użyciu kodu.
W poniższym przykładzie pokazano, jak załadować Page bezpośrednio do Frame (pageFrame
) przy użyciu kodu.
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
Poniższy przykład jest odpowiednikiem znaczników poprzedniego przykładu.
<Frame Name="pageFrame" Source="PageContentFile.xaml" />
Miejsce pochodzenia plików
Pliki zasobów mają jawną relację z zestawami, z którymi są dystrybuowane, zgodnie z definicją AssemblyAssociatedContentFileAttribute. Jednak czasami może być konieczne ustanowienie niejawnej lub nieistniejącej relacji między zestawem a plikiem danych aplikacji, w tym w następujących przypadkach:
Plik nie istnieje w czasie kompilacji.
Nie wiesz, jakie pliki będzie wymagał Twój zestaw, dopóki nie zostanie uruchomiony.
Chcesz mieć możliwość aktualizowania plików bez ponownego komplikowania zestawu, z którym są skojarzone.
Aplikacja używa dużych plików danych, takich jak audio i wideo, i chcesz, aby użytkownicy mogli je pobrać tylko wtedy, gdy zdecydują się.
Można załadować te typy plików przy użyciu tradycyjnych schematów identyfikatorów URI, takich jak schematy file:///
i http://
.
<Image Source="file:///C:/DataFile.bmp" />
<Image Source="http://www.datafilewebsite.com/DataFile.bmp" />
Jednak schematy file:///
i http://
wymagają, aby aplikacja miała pełne zaufanie. Jeśli aplikacja jest aplikacją przeglądarki XAML (XBAP), która została uruchomiona z Internetu lub intranetu, i żąda tylko zestawu uprawnień dozwolonych dla aplikacji uruchamianych z tych lokalizacji, luźne pliki mogą być ładowane tylko z witryny źródła aplikacji (lokalizacja uruchamiania). Takie pliki są nazywane lokacją źródła plików.
Lokacja plików pochodzenia jest jedyną opcją dla aplikacji częściowo zaufanych, chociaż nie jest ograniczona do aplikacji częściowo zaufanych. Aplikacje o pełnym zaufaniu mogą nadal wymagać załadowania plików danych aplikacji, o których nie wiedzą w czasie kompilacji; Chociaż aplikacje o pełnym zaufaniu mogą używać file:///, prawdopodobnie pliki danych aplikacji zostaną zainstalowane w tym samym folderze co podfolder zestawu aplikacji. W takim przypadku używanie odwołania do lokacji pochodzenia jest łatwiejsze niż użycie file:///, ponieważ użycie file:/// wymaga wypracowania pełnej ścieżki pliku.
Notatka
Lokacja plików pochodzenia nie jest buforowana za pomocą aplikacji przeglądarki XAML (XBAP) na komputerze klienckim, podczas gdy pliki zawartości są. W związku z tym są pobierane tylko wtedy, gdy są one specjalnie żądane. Jeśli aplikacja przeglądarki XAML (XBAP) ma duże pliki multimedialne, skonfigurowanie ich jako lokacji plików pochodzenia oznacza, że początkowe uruchamianie aplikacji jest znacznie szybsze, a pliki są pobierane tylko na żądanie.
Konfigurowanie lokacji plików pochodzenia
Jeśli witryna plików pochodzenia nie istnieje lub nie jest znana w czasie kompilacji, należy użyć tradycyjnych mechanizmów wdrażania w celu zapewnienia, że wymagane pliki są dostępne w czasie wykonywania, w tym przy użyciu XCopy
programu wiersza polecenia lub Instalatora Microsoft Windows.
Jeśli wiesz w czasie kompilacji pliki, które mają znajdować się w lokacji źródła, ale nadal chcesz uniknąć jawnej zależności, możesz dodać te pliki do projektu MSBuild jako element None
. Podobnie jak w przypadku plików zawartości, należy ustawić atrybut msBuild CopyToOutputDirectory
, aby określić, że lokacja pliku pochodzenia jest kopiowana do lokalizacji powiązanej z utworzonym zestawem, określając wartość Always
lub wartość PreserveNewest
.
<Project xmlns="http://schemas.microsoft.com/developer/msbuild/2003" ... >
...
<None Include="PageSiteOfOriginFile.xaml">
<CopyToOutputDirectory>Always</CopyToOutputDirectory>
</None>
...
</Project>
Notatka
W programie Visual Studio tworzysz plik pochodzenia witryny, dodając plik do projektu i ustawiając jego Build Action
na None
.
Podczas kompilowania projektu program MSBuild kopiuje określone pliki do folderu wyjściowego kompilacji.
Korzystanie z plików pochodzących z witryny źródłowej
Aby załadować lokację pliku pochodzenia, można wywołać metodę GetRemoteStream klasy Application, przekazując identyfikator URI pakietu, który identyfikuje żądaną lokację pliku pochodzenia. GetRemoteStream zwraca obiekt StreamResourceInfo, który uwidacznia witrynę pliku pochodzenia jako Stream i opisuje jego typ zawartości.
Na przykład poniższy kod pokazuje, w jaki sposób użyć GetRemoteStream, aby załadować plik witryny pochodzenia Page i ustawić go jako zawartość 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
Wywołanie GetRemoteStream zapewnia dostęp do Stream, ale trzeba dodatkowo przekonwertować go na typ właściwości, którą będzie ustawiany. Zamiast tego można pozwolić WPF zająć się otwieraniem i konwertowaniem Stream, ładując plik zasobu bezpośrednio do właściwości typu za pomocą kodu.
W poniższym przykładzie pokazano, jak załadować Page bezpośrednio do Frame (pageFrame
) przy użyciu kodu.
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
Poniższy przykład jest odpowiednikiem w postaci znaczników poprzedniego przykładu.
<Frame Name="pageFrame" Source="pack://siteoforigin:,,,/SiteOfOriginFile.xaml" />
Ponowne kompilowanie po zmianie typu kompilacji
Po zmianie typu kompilacji pliku danych aplikacji należy ponownie skompilować całą aplikację, aby upewnić się, że te zmiany zostaną zastosowane. Jeśli tylko skompilujesz aplikację, zmiany nie zostaną zastosowane.
Zobacz też
- identyfikatory URI pakietu w WPF
.NET Desktop feedback