Udostępnij za pomocą


Kompilowanie aplikacji WPF

Aplikacje programu Windows Presentation Foundation (WPF) można tworzyć jako pliki wykonywalne programu .NET Framework (.exe), biblioteki (.dll) lub kombinację obu typów zestawów. W tym temacie przedstawiono sposób kompilowania aplikacji WPF i opisano kluczowe kroki procesu kompilacji.

Tworzenie aplikacji WPF

Aplikację WPF można skompilować w następujący sposób:

Potok kompilacji WPF

Podczas kompilowania projektu WPF wywoływana jest kombinacja elementów docelowych specyficznych dla języka i WPF. Proces realizacji tych celów nazywany jest potokiem budowania, a kluczowe kroki przedstawiono na poniższym rysunku.

Proces kompilacji WPF

Inicjalizacje przed budowaniem

Przed utworzeniem program MSBuild określa lokalizację ważnych narzędzi i bibliotek, w tym następujące:

  • The .NET Framework.

  • Katalogi zestawu Windows SDK.

  • Lokalizacja zestawów odwołań WPF.

  • Właściwość ścieżek wyszukiwania zestawów.

Pierwszą lokalizacją, w której program MSBuild wyszukuje zestawy, jest katalog plików odwołań (%ProgramFiles%\Reference Assemblies\Microsoft\Framework\v3.0\). W tym kroku proces kompilacji inicjuje również różne właściwości i grupy elementów i wykonuje wszelkie wymagane prace oczyszczania.

Rozwiązywanie odwołań

Proces kompilacji lokalizuje i wiąże zestawy wymagane do skompilowania projektu aplikacji. Ta logika jest zawarta w zadaniu ResolveAssemblyReference. Wszystkie zestawy zadeklarowane jako Reference w pliku projektu są dostarczane do zadania wraz z informacjami na temat ścieżek wyszukiwania i metadanych zestawów już zainstalowanych w systemie. Zadanie wyszukuje zestawy i używa metadanych zainstalowanego zestawu do filtrowania tych podstawowych zestawów WPF, które nie muszą być wyświetlane w manifestach wyjściowych. Należy to zrobić, aby uniknąć nadmiarowych informacji w manifestach ClickOnce. Na przykład, ponieważ PresentationFramework.dll można uznać za przedstawiciela aplikacji utworzonej na platformie WPF, a wszystkie zestawy WPF istnieją w tej samej lokalizacji na każdym komputerze z zainstalowanym programem .NET Framework, nie ma potrzeby dołączania wszystkich informacji o wszystkich zestawach referencyjnych programu .NET Framework w manifestach.

Kompilacja znaczników — etap 1

W tym kroku pliki XAML są analizowane i kompilowane, dzięki czemu środowisko uruchomieniowe nie poświęca czasu na analizowanie kodu XML i weryfikowanie wartości właściwości. Skompilowany plik XAML jest wstępnie tokenizowany, dzięki czemu ładowanie pliku XAML w czasie wykonywania powinno być znacznie szybsze niż ładowanie pliku XAML.

W tym kroku są wykonywane następujące działania dla każdego pliku XAML, który jest elementem Page kompilacji:

  1. Plik XAML jest analizowany przez kompilator znaczników.

  2. Skompilowana reprezentacja jest tworzona dla tego kodu XAML i kopiowana do folderu obj\Release.

  3. Zostanie utworzona reprezentacja CodeDOM nowej klasy częściowej i skopiowana do folderu obj\Release.

Ponadto plik kodu specyficzny dla języka jest generowany dla każdego pliku XAML. Na przykład, dla strony Page1.xaml w projekcie Visual Basic generowany jest Page1.g.vb, a dla strony Page1.xaml w projekcie C# generowany jest Page1.g.cs. Znak ".g" w nazwie pliku wskazuje, że plik jest plikiem generowanego kodu z częściową deklaracją klasy dla elementu najwyższego poziomu pliku markup (na przykład Page lub Window). Klasa jest zadeklarowana za pomocą partial modyfikatora w języku C# (Extends w Visual Basic), aby wskazać, że istnieje inna deklaracja dla klasy w innym miejscu, zwykle w pliku za kodem Page1.xaml.cs.

Klasa częściowa rozciąga się od odpowiedniej klasy bazowej (takiej jak Page dla strony) i implementuje System.Windows.Markup.IComponentConnector interfejs. Interfejs IComponentConnector zawiera metody inicjowania składnika i łączenia nazw i zdarzeń na elementach w jego zawartości. W związku z tym wygenerowany plik kodu ma implementację metody podobną do następującej:

public void InitializeComponent() {
    if (_contentLoaded) {
        return;
    }
    _contentLoaded = true;
    System.Uri resourceLocater =
        new System.Uri(
            "window1.xaml",
            System.UriKind.RelativeOrAbsolute);
    System.Windows.Application.LoadComponent(this, resourceLocater);
}
Public Sub InitializeComponent() _

    If _contentLoaded Then
        Return
    End If

    _contentLoaded = True
    Dim resourceLocater As System.Uri = _
        New System.Uri("mainwindow.xaml", System.UriKind.Relative)

    System.Windows.Application.LoadComponent(Me, resourceLocater)

End Sub

Domyślnie kompilacja znaczników jest uruchamiana w taki sam sposób AppDomain jak aparat MSBuild. Zapewnia to znaczne wzrosty wydajności. To zachowanie może być przełączane przy pomocy właściwości AlwaysCompileMarkupFilesInSeparateDomain. Ma to zaletę w odciążaniu wszystkich zestawów referencyjnych przez odciążenie oddzielnego AppDomain.

Kompilacja znaczników — etap 2

Nie wszystkie strony XAML są kompilowane podczas pierwszej fazy kompilacji znaczników. Pliki XAML, które mają lokalnie zdefiniowane odwołania do typów (odwołania do typów zdefiniowanych w kodzie w innym miejscu tego samego projektu) są obecnie wykluczone z kompilacji. Dzieje się tak, ponieważ te lokalnie zdefiniowane typy istnieją tylko w źródle i nie zostały jeszcze skompilowane. Aby to określić, analizator używa heurystyki, które obejmują wyszukiwanie elementów, takich jak x:Name w pliku znaczników. Po znalezieniu takiego wystąpienia kompilacja pliku znaczników jest odroczona do momentu skompilowania plików kodu, po czym druga faza kompilacji znaczników przetwarza te pliki.

Klasyfikacja plików

Proces kompilacji umieszcza pliki wyjściowe w różnych grupach zasobów na podstawie zestawu aplikacji, w którym zostaną umieszczone. W typowej aplikacji nielokalizowanej wszystkie pliki danych oznaczone jako Resource są umieszczane w głównym zestawie (wykonywalnym lub bibliotece). Po ustawieniu UICulture w projekcie, wszystkie skompilowane pliki XAML oraz te zasoby, które są specjalnie oznaczone jako specyficzne dla języka, zostają umieszczone w satelitarnym zestawie zasobów. Ponadto wszystkie zasoby neutralne językowo są umieszczane w głównym zestawie. W tym kroku procesu kompilacji jest to określone.

Akcje kompilacji ApplicationDefinition, Page i Resource w pliku projektu mogą być wzbogacone o metadane Localizable (dopuszczalne wartości to true i false), które określają, czy plik jest specyficzny dla języka, czy neutralny.

Kompilacja podstawowa

Podstawowy krok kompilacji obejmuje kompilację plików kodu. Jest to orkiestrowane przez logikę w plikach docelowych specyficznych dla języka Microsoft.CSharp.targets i Microsoft.VisualBasic.targets. Jeśli heurystyka ustaliła, że wystarczy jednokrotne przejście przez kompilator znaczników, zostanie wygenerowane główne zestawienie. Jeśli jednak co najmniej jeden plik XAML w projekcie zawiera odwołania do typów zdefiniowanych lokalnie, zostanie wygenerowany tymczasowy plik .dll, aby końcowe zestawy aplikacji mogły zostać utworzone po zakończeniu drugiego przekazywania kompilacji znaczników.

Generowanie manifestu

Po zakończeniu procesu kompilacji, kiedy wszystkie zestawy aplikacji i pliki zawartości są gotowe, generowane są manifesty ClickOnce dla aplikacji.

Plik manifestu wdrożenia opisuje model wdrażania: bieżącą wersję, zachowanie aktualizacji i tożsamość wydawcy wraz z podpisem cyfrowym. Ten manifest ma być utworzony przez administratorów, którzy obsługują wdrażanie. Rozszerzenie pliku to .xbap (dla aplikacji przeglądarki XAML (XBAPs)) i .application dla zainstalowanych aplikacji. Pierwszy element jest dyktowany przez HostInBrowser właściwość projektu, a w rezultacie manifest identyfikuje aplikację jako hostowaną w przeglądarce.

Manifest aplikacji (plik manifestu .exe) opisuje zestawy aplikacji i biblioteki zależne oraz wyświetla listę uprawnień wymaganych przez aplikację. Ten plik ma zostać utworzony przez dewelopera aplikacji. Aby uruchomić aplikację ClickOnce, użytkownik otwiera plik manifestu wdrożenia aplikacji.

Te pliki manifestu są zawsze tworzone dla XBAPs. W przypadku zainstalowanych aplikacji te elementy nie są tworzone, chyba że taka właściwość GenerateManifests jest określona w pliku projektu o wartości true.

XBAPy uzyskują dwa dodatkowe uprawnienia ponad te przypisane typowym aplikacjom strefy internetowej: WebBrowserPermission i MediaPermission. System kompilacji WPF deklaruje te uprawnienia w manifeście aplikacji.

Obsługa kompilacji przyrostowej

System kompilacji WPF zapewnia obsługę kompilacji przyrostowych. Jest wystarczająco inteligentny odnośnie wykrywania zmian wprowadzonych w znacznikach lub kodzie i kompiluje tylko te artefakty, których dotyczy zmiana. Mechanizm kompilacji przyrostowej używa następujących plików:

  • Plik $(AssemblyName)_MarkupCompiler.Cache w celu zachowania bieżącego stanu kompilatora.

  • Plik $(AssemblyName)_MarkupCompiler.lref do buforowania plików XAML z odwołaniami do lokalnie zdefiniowanych typów.

Poniżej przedstawiono zestaw reguł dotyczących kompilacji przyrostowej:

  • Plik jest najmniejszą jednostką, w której system kompilacji wykrywa zmianę. W przypadku pliku kodu system kompilacji nie może określić, czy typ został zmieniony lub czy został dodany kod. To samo dotyczy plików projektów.

  • Mechanizm kompilacji przyrostowej musi być świadomy, że strona XAML definiuje klasę lub używa innych klas.

  • Jeśli Reference wpisy zostaną zmienione, ponownie skompiluj wszystkie strony.

  • Jeśli plik kodu ulegnie zmianie, ponownie skompiluj wszystkie strony przy użyciu odwołań do typu zdefiniowanego lokalnie.

  • Jeśli plik XAML ulegnie zmianie:

    • Jeśli kod XAML jest zadeklarowany jako Page w projekcie: jeśli kod XAML nie ma lokalnie zdefiniowanych odwołań do typu, ponownie skompiluj kod XAML i wszystkie strony XAML z lokalnymi odwołaniami; jeśli kod XAML zawiera odwołania lokalne, ponownie skompiluj wszystkie strony XAML z lokalnymi odwołaniami.

    • Jeśli kod XAML jest zadeklarowany jako ApplicationDefinition w projekcie: przekompiluj wszystkie strony XAML (przyczyna: każdy kod XAML ma odwołanie do Application typu, który mógł ulec zmianie).

  • Jeśli plik projektu deklaruje plik kodu jako definicję aplikacji zamiast pliku XAML:

    • Sprawdź, czy ApplicationClassName wartość w pliku projektu została zmieniona (czy istnieje nowy typ aplikacji?). Jeśli tak, ponownie skompiluj całą aplikację.

    • W przeciwnym razie ponownie skompiluj wszystkie strony XAML przy użyciu lokalnych odwołań.

  • Jeśli plik projektu ulegnie zmianie: zastosuj wszystkie powyższe reguły i sprawdź, co należy ponownie skompilować. Zmiany w następujących właściwościach wyzwalają kompletną ponowną kompilację: AssemblyName, , IntermediateOutputPathRootNamespacei HostInBrowser.

Możliwe są następujące scenariusze ponownego kompilu:

  • Cała aplikacja zostanie ponownie skompilowana.

  • Tylko te pliki XAML, które mają lokalnie zdefiniowane odwołania do typów, są ponownie komilowane.

  • Nic nie zostanie ponownie skompilowane (jeśli nic w projekcie nie uległo zmianie).

Zobacz także