Kompilieren einer WPF-Anwendung
Windows Presentation Foundation (WPF)-Anwendungen können als ausführbare .NET Framework-Dateien (.exe), Bibliotheken (.dll) oder eine Kombination aus beiden Assemblytypen erstellt werden. In diesem Artikel wird beschrieben, wie WPF-Anwendungen erstellt werden, und die wichtigsten Schritte im Buildprozess werden erläutert.
Erstellen einer WPF-Anwendung
Eine WPF-Anwendung kann wie folgt kompiliert werden:
Befehlszeile: Die Anwendung darf nur Code (kein XAML) und eine Anwendungsdefinitionsdatei enthalten. Weitere Informationen finden Sie unter Erstellen über die Befehlszeile mit csc.exe oder Erstellen über die Befehlszeile (Visual Basic).
Microsoft Build Engine (MSBuild). Zusätzlich zu den Code- und XAML-Dateien muss die Anwendung eine MSBuild-Projektdatei enthalten. Weitere Informationen finden Sie unter "MSBuild".
Visual Studio. Visual Studio ist eine integrierte Entwicklungsumgebung, die WPF-Anwendungen mit MSBuild kompiliert und einen visuellen Designer zum Erstellen der Benutzeroberfläche enthält. Weitere Informationen finden Sie unter Schreiben und Verwalten von Code mit Visual Studio und Design-XAML in Visual Studio.
WPF-Buildpipeline:
Beim Erstellen eines WPF-Projekts wird die Kombination aus sprachspezifischen und WPF-spezifischen Zielen aufgerufen. Das Ausführen dieser Ziele wird als Buildpipeline bezeichnet. Die wichtigsten Schritte werden in der folgenden Abbildung dargestellt.
Präbuildinitialisierungen
Vor Beginn der Erstellung bestimmt MSBuild den Speicherort wichtiger Tools und Bibliotheken (einschließlich der folgenden):
The .NET Framework.
Die Windows SDK-Verzeichnisse.
Speicherort von WPF-Verweisassemblys
Eigenschaft für die Assemblysuchpfade
Der erste Speicherort, an dem MSBuild nach Assemblys sucht, ist das Referenzassemblysverzeichnis (%ProgramFiles%\Reference Assemblies\Microsoft\Framework\v3.0\). In diesem Schritt initialisiert der Buildprozess auch die verschiedenen Eigenschaften und Elementgruppen und führt die erforderlichen Bereinigungen durch.
Auflösen von Verweisen
Der Buildprozess lokalisiert und bindet die Assemblies, die zum Erstellen des Anwendungsprojekts erforderlich sind. Diese Logik ist in Aufgabe ResolveAssemblyReference
enthalten. Alle in der Projektdatei als Reference
deklarierten Assemblys werden der Aufgabe mit Informationen zu Suchpfaden und Metadaten für Assemblys zur Verfügung gestellt, die bereits im System installiert sind. Die Aufgabe sucht Assemblys auf und verwendet die Metadaten der installierten Assembly, um die WPF-Kernassemblys herauszufiltern, die nicht in den Ausgabemanifesten angezeigt werden müssen. Dies geschieht, um redundante Informationen in den ClickOnce-Manifesten zu vermeiden. Da PresentationFramework.dll beispielsweise als repräsentativ für eine Anwendung gelten kann, die auf und für WPF basiert, und da alle WPF-Assemblys an demselben Speicherort auf jedem Computer vorhanden sind, auf dem .NET Framework installiert ist, müssen nicht alle Informationen zu allen .NET Framework-Referenzassemblys in die Manifeste eingeschlossen werden.
Markupkompilierungsdurchlauf 1
In diesem Schritt werden XAML-Dateien analysiert und kompiliert, sodass die Laufzeit keine Zeit für die Analyse von XML und das Validieren von Eigenschaftswerten aufwendet. Die kompilierte XAML-Datei ist vorab tokenisiert, sodass das Laden zur Laufzeit wesentlich schneller sein sollte als das Laden einer XAML-Datei.
Während dieses Schritts werden die folgenden Aktivitäten für jede XAML-Datei ausgeführt, die ein Page
Buildelement ist:
Die XAML-Datei wird vom Markupcompiler analysiert.
Für diesen XAML-Code wird eine kompilierte Darstellung erstellt und in den Ordner "obj\Release" kopiert.
Eine CodeDOM-Darstellung einer neuen partiellen Klasse wird erstellt und in den Ordner "obj\Release" kopiert.
Darüber hinaus wird für jede XAML-Datei eine sprachspezifische Codedatei generiert. Für eine Page1.xaml-Seite in einem Visual Basic-Projekt wird beispielsweise die Datei „Page1.g.vb“ generiert und für eine Page1.xaml-Seite in einem C#-Projekt die Datei „Page1.g.cs“. Das „.g“ im Dateinamen gibt an, dass die Datei generierten Code darstellt, der über eine Deklaration der partiellen Klasse für das Element der obersten Ebene der Markupdatei verfügt (z. B. Page
oder Window
). Die Klasse wird mit dem partial
Modifizierer in C# (Extends
in Visual Basic) deklariert, um anzugeben, dass an anderer Stelle, in der Regel in der CodeBehind-Datei Page1.xaml.cs, eine weitere Deklaration für die Klasse vorhanden ist.
Die partielle Klasse erstreckt sich von der entsprechenden Basisklasse (z. B. Page für eine Seite) und implementiert die System.Windows.Markup.IComponentConnector Schnittstelle. Die IComponentConnector-Schnittstelle verfügt über Methoden zum Initialisieren einer Komponente und um Namen und Ereignisse mit Elementen in ihrem Inhalt zu verknüpfen. Folglich verfügt die generierte Codedatei über eine Methodenimplementierung wie die folgenden:
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
Standardmäßig wird die Markupkompilierung in derselben AppDomain ausgeführt wie die MSBuild-Engine. Dies bietet erhebliche Leistungssteigerungen. Dieses Verhalten kann mit der AlwaysCompileMarkupFilesInSeparateDomain
-Eigenschaft geändert werden. Dies hat den Vorteil, dass alle Verweisassemblys durch Entladen der separaten AppDomain entladen werden.
Markupkompilierungsdurchlauf 2
Während des Durchlaufs 1 der Markupkompilierung werden nicht alle XAML-Seiten kompiliert. XAML-Dateien, die lokal definierte Typverweise enthalten (Verweise auf Typen, die an anderer Stelle im selben Projekt im Code definiert sind), sind momentan von der Kompilierung ausgenommen. Dies liegt daran, dass diese lokal definierten Typen nur in der Quelle vorhanden sind und noch nicht kompiliert wurden. Um dies zu bestimmen, verwendet der Parser heuristische Verfahren, die das Suchen nach Elementen umfassen (z. B. x:Name
in der Markupdatei). Wird eine solche Instanz gefunden, wird die Kompilierung der Markupdatei bis zur Kompilierung der Codedateien zurückgestellt. Anschließend werden diese Dateien im zweiten Durchlauf der Markupkompilierung verarbeitet.
Dateiklassifizierung
Der Buildprozess ordnet Ausgabedateien verschiedenen Ressourcengruppen zu, je nachdem, in welche Anwendungszusammenstellung sie aufgenommen werden. In einer normalen, nicht lokalisierten Anwendung werden alle als Resource
markierten Datendateien in der Hauptassembly platziert (ausführbare Datei oder Bibliothek). Wenn UICulture
im Projekt festgelegt wird, werden alle kompilierten XAML-Dateien sowie die Ressourcen, die speziell als sprachspezifisch gekennzeichnet sind, in der Satellitenressourcen-Assemblierung platziert. Außerdem werden alle sprachunabhängigen Ressourcen in die Hauptassembly eingefügt. In diesem Schritt des Buildprozesses wird diese Bestimmung vorgenommen.
Die Build-Aktionen ApplicationDefinition
, Page
und Resource
können in der Projektdatei mit den Metadaten Localizable
erweitert werden (zulässige Werte sind true
und false
), wodurch festgelegt wird, ob die Datei sprachspezifisch oder -neutral ist.
Kernkompilierung
Der Hauptkompilierungsschritt umfasst die Kompilierung von Codedateien. Dies wird durch Logik in den sprachspezifischen Zieldateien "Microsoft.CSharp.targets" und "Microsoft.VisualBasic.targets" koordiniert. Die Hauptassembly wird generiert, wenn die Heuristik einen einzelnen Durchlauf des Markupcompilers als ausreichend einschätzt. Wenn jedoch eine oder mehrere XAML-Dateien im Projekt Verweise auf lokal definierte Typen haben, wird eine temporäre .dll Datei generiert, sodass die endgültigen Anwendungsassemblys nach Abschluss des zweiten Markupkompilierungsvorgangs erstellt werden können.
Manifestgenerierung
Nachdem alle Anwendungsassemblys und Inhaltsdateien fertiggestellt wurden, werden die ClickOnce-Manifeste am Ende des Buildprozesses für die Anwendung generiert.
Die Bereitstellungsmanifestdatei beschreibt das Bereitstellungsmodell: die aktuelle Version, das Updateverhalten und die Herausgeberidentität sowie die digitale Signatur. Dieses Manifest soll von Administratoren erstellt werden, die für die Bereitstellung zuständig sind. Die Dateierweiterung ist .xbap (für XAML-Browseranwendungen (XBAPs)) und .application für installierte Anwendungen. Erstere wird durch die HostInBrowser
-Projekteigenschaft vorgeschrieben. Als Ergebnis identifiziert das Manifest die Anwendung als vom Browser gehostet.
Das Anwendungsmanifest (eine .exe.manifest-Datei) beschreibt die Anwendungsassemblys und abhängigen Bibliotheken und listet Berechtigungen auf, die von der Anwendung benötigt werden. Diese Datei soll vom Anwendungsentwickler erstellt werden. Um eine ClickOnce-Anwendung zu starten, öffnet ein Benutzer die Bereitstellungsmanifestdatei der Anwendung.
Diese Manifestdateien werden immer für XBAPs erstellt. Für installierte Anwendungen werden sie nicht erstellt, sofern die GenerateManifests
-Eigenschaft in der Projektdatei nicht mit dem Wert true
angegeben wird.
XBAPs erhalten zwei zusätzliche Berechtigungen neben denjenigen, die typischen Internetzonenanwendungen zugewiesen werden: WebBrowserPermission und MediaPermission. Das WPF-Buildsystem deklariert diese Berechtigungen im Anwendungsmanifest.
Unterstützung für inkrementelle Builds
Das WPF-Buildsystem bietet Unterstützung für inkrementelle Builds. Es erkennt recht intelligent Änderungen am Markup oder Code und kompiliert nur die Artefakte, die von der Änderung betroffen sind. Der inkrementelle Buildmechanismus verwendet die folgenden Dateien:
Eine $(AssemblyName)_MarkupCompiler.Cache-Datei, um den aktuellen Compilerzustand beizubehalten.
Eine $(AssemblyName)_MarkupCompiler.lref-Datei, um die XAML-Dateien mit Verweisen auf lokal definierte Typen zwischenzuspeichern.
Im Folgenden finden Sie Regeln für inkrementelle Builds:
Die Datei ist die kleinste Einheit, bei der das Buildsystem Änderungen erkennt. Für eine Codedatei kann das Buildsystem also nicht feststellen, ob ein Typ geändert wurde oder ob Code hinzugefügt wurde. Gleiches gilt für Projektdateien.
Der inkrementelle Buildmechanismus muss erkennen, dass eine XAML-Seite entweder eine Klasse definiert oder andere Klassen verwendet.
Wenn
Reference
Einträge geändert werden, kompilieren Sie alle Seiten erneut.Wenn sich eine Codedatei ändert, kompilieren Sie alle Seiten mit lokal definierten Typverweisen neu.
Wenn sich eine XAML-Datei ändert:
Wenn XAML im Projekt als
Page
deklariert ist: Wenn das XAML keine lokal definierten Typverweise hat, kompilieren Sie dieses XAML zusammen mit allen XAML-Seiten mit lokalen Verweisen neu; Wenn das XAML lokale Verweise enthält, kompilieren Sie alle XAML-Seiten mit lokalen Verweisen neu.Wenn XAML im Projekt als
ApplicationDefinition
deklariert wird: Kompilieren Sie alle XAML-Seiten neu (Grund: Jede XAML-Seite hat einen Verweis auf einen Application-Typ, der sich möglicherweise geändert hat).
Wenn die Projektdatei eine Codedatei anstelle einer XAML-Datei als Anwendungsdefinition deklariert:
Überprüfen Sie, ob sich der
ApplicationClassName
Wert in der Projektdatei geändert hat (gibt es einen neuen Anwendungstyp?). Wenn ja, kompilieren Sie die gesamte Anwendung erneut.Kompilieren Sie andernfalls alle XAML-Seiten mit lokalen Referenzen neu.
Wenn sich eine Projektdatei ändert: Wenden Sie alle vorherigen Regeln an, und sehen Sie, was neu kompiliert werden muss. Änderungen an den folgenden Eigenschaften lösen eine vollständige Neukompilierung aus:
AssemblyName
,IntermediateOutputPath
,RootNamespace
undHostInBrowser
.
Die folgenden Neukompilierungsszenarien sind möglich:
Die gesamte Anwendung wird neu kompiliert.
Nur die XAML-Dateien, die lokal definierte Typverweise enthalten, werden neu kompiliert.
Nichts wird neu kompiliert (wenn sich nichts im Projekt geändert hat).
Siehe auch
.NET Desktop feedback