Condividi tramite


Compilare un'applicazione WPF

Le applicazioni Windows Presentation Foundation (WPF) possono essere compilate come eseguibili di .NET Framework (.exe), librerie (.dll) o una combinazione di entrambi i tipi di assembly. Questo argomento illustra come compilare applicazioni WPF e descrive i passaggi principali del processo di compilazione.

Compilazione di un'applicazione WPF

Un'applicazione WPF può essere compilata nei modi seguenti:

  • Riga di comando. L'applicazione deve contenere solo codice (senza XAML) e un file di definizione dell'applicazione. Per altre informazioni, vedere Compilazione da riga di comando con csc.exe o Compilazione dalla riga di comando (Visual Basic).For more information, see Command-line Building With csc.exeor Building from the Command Line (Visual Basic).

  • Microsoft Build Engine (MSBuild). Oltre al codice e ai file XAML, l'applicazione deve contenere un file di progetto MSBuild. Per altre informazioni, vedere "MSBuild".

  • Visual Studio. Visual Studio è un ambiente di sviluppo integrato che compila applicazioni WPF con MSBuild e include una finestra di progettazione visiva per la creazione dell'interfaccia utente. Per altre informazioni, vedere Scrivere e gestire codice con Visual Studio e Progettare XAML in Visual Studio.

Pipeline di compilazione WPF

Quando viene compilato un progetto WPF, viene richiamata la combinazione di destinazioni specifiche del linguaggio e specifiche di WPF. Il processo di esecuzione di questi obiettivi è denominato build pipeline e i passaggi chiave sono illustrati nella figura seguente.

Processo di build WPF

Inizializzazioni pre-build

Prima della compilazione, MSBuild determina la posizione di strumenti e librerie importanti, tra cui:

  • The .NET Framework.

  • Directory di Windows SDK.

  • La posizione degli assembly di riferimento WPF.

  • Proprietà per i percorsi di ricerca dell'assembly.

Il primo percorso in cui MSBuild cerca gli assembly è la directory dell'assembly di riferimento (%ProgramFiles%\Reference Assemblies\Microsoft\Framework\v3.0\). Durante questo passaggio, il processo di compilazione inizializza anche le varie proprietà e i gruppi di elementi ed esegue qualsiasi operazione di pulizia necessaria.

Risoluzione dei riferimenti

Il processo di compilazione individua e associa gli assembly necessari per compilare il progetto dell'applicazione. Questa logica è contenuta nell'attività ResolveAssemblyReference . Tutti gli assembly dichiarati come Reference nel file di progetto vengono forniti all'attività insieme alle informazioni sui percorsi di ricerca e sui metadati negli assembly già installati nel sistema. L'attività cerca gli assembly e usa i metadati dell'assembly installato per filtrare gli assembly WPF di base che non devono essere visualizzati nei manifesti di output. Questa operazione viene eseguita per evitare informazioni ridondanti nei manifesti ClickOnce. Ad esempio, poiché PresentationFramework.dll può essere considerato rappresentativo di un'applicazione basata su e per WPF e poiché tutti gli assembly WPF esistono nella stessa posizione in ogni computer in cui è installato .NET Framework, non è necessario includere tutte le informazioni su tutti gli assembly di riferimento di .NET Framework nei manifesti.

Compilazione del markup- Passaggio 1

In questo passaggio i file XAML vengono analizzati e compilati in modo che il runtime non passi tempo ad analizzare XML e convalidare i valori delle proprietà. Il file XAML compilato viene pre-tokenizzato in modo che, in fase di esecuzione, il caricamento sia molto più veloce rispetto al caricamento di un file XAML.

Durante questo passaggio vengono eseguite le attività seguenti per ogni file XAML che è un Page elemento di compilazione:

  1. Il file XAML viene analizzato dal compilatore di markup.

  2. Viene creata una rappresentazione compilata per il codice XAML e copiata nella cartella obj\Release.

  3. Viene creata e copiata una rappresentazione CodeDOM di una nuova classe parziale nella cartella obj\Release.

Inoltre, viene generato un file di codice specifico del linguaggio per ogni file XAML. Ad esempio, per una pagina Page1.xaml in un progetto Visual Basic, viene generata una Page1.g.vb; per una pagina Page1.xaml in un progetto C#, viene generata una Page1.g.cs. ".g" nel nome del file indica che il file viene generato codice con una dichiarazione di classe parziale per l'elemento di primo livello del file di markup ( ad esempio Page o Window). La classe viene dichiarata con il partial modificatore in C# (Extends in Visual Basic) per indicare che è presente un'altra dichiarazione per la classe altrove, in genere nel file code-behind Page1.xaml.cs.

La classe parziale si estende dalla classe base appropriata (ad esempio Page per una pagina) e implementa l'interfaccia System.Windows.Markup.IComponentConnector . L'interfaccia IComponentConnector include metodi per inizializzare un componente e connettere nomi ed eventi sugli elementi nel relativo contenuto. Di conseguenza, il file di codice generato ha un'implementazione del metodo simile alla seguente:

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

Per impostazione predefinita, la compilazione di markup viene eseguita nello stesso AppDomain modo del motore MSBuild. In questo modo si ottiene un miglioramento significativo delle prestazioni. Questo comportamento può essere attivato o disattivato con la proprietà AlwaysCompileMarkupFilesInSeparateDomain. Questo ha il vantaggio di scaricare tutti gli assembly di riferimento scaricando separatamente l'assembly AppDomain.

Compilazione di markup: Passaggio 2

Non tutte le pagine XAML vengono compilate durante il passaggio 1 della compilazione del markup. I file XAML con riferimenti di tipo definiti localmente (riferimenti ai tipi definiti nel codice altrove nello stesso progetto) sono esentati dalla compilazione in questo momento. Ciò avviene perché questi tipi definiti localmente esistono solo nell'origine e non sono ancora stati compilati. Per determinare questo problema, il parser usa euristica che implica la ricerca di elementi come x:Name nel file di markup. Quando viene trovata un'istanza di questo tipo, la compilazione del file di markup viene posticipata fino alla compilazione dei file di codice, dopo di che la seconda compilazione di markup elabora questi file.

Classificazione file

Il processo di compilazione inserisce i file di output in gruppi di risorse diversi in base all'assembly dell'applicazione in cui verranno inseriti. In un'applicazione tipica non localizzata, tutti i file di dati contrassegnati come Resource vengono inseriti nell'assembly principale (eseguibile o libreria). Quando UICulture viene impostato nel progetto, tutti i file XAML compilati e le risorse contrassegnate specificamente come specifiche del linguaggio vengono inserite nell'assembly di risorse satellite. Inoltre, tutte le risorse neutre rispetto alla lingua vengono inserite nell'assembly principale. In questo passaggio del processo di compilazione viene eseguita la determinazione.

Le azioni di compilazione ApplicationDefinition, Page e Resource nel file di progetto possono essere aumentate con il metadato Localizable (i valori accettabili sono true e false), che determina se il file è specifico del linguaggio o neutro rispetto al linguaggio.

Compilazione principale

Il passaggio di compilazione principale prevede la compilazione di file di codice. Questa operazione è orchestrata dalla logica nei file di destinazione specifici del linguaggio Microsoft.CSharp.targets e Microsoft.VisualBasic.targets. Se l'euristica ha determinato che un singolo passaggio del compilatore di markup è sufficiente, viene generato l'assembly principale. Tuttavia, se uno o più file XAML nel progetto hanno riferimenti a tipi definiti in locale, viene generato un file di .dll temporaneo in modo che gli assembly dell'applicazione finali possano essere creati dopo il completamento della seconda fase di compilazione del markup.

Generazione del manifesto

Al termine del processo di compilazione, dopo che tutti gli assembly e i file di contenuto dell'applicazione sono pronti, vengono generati i manifesti ClickOnce per l'applicazione.

Il file manifesto della distribuzione descrive il modello di distribuzione: la versione corrente, il comportamento di aggiornamento e l'identità dell'editore insieme alla firma digitale. Questo manifesto deve essere creato dagli amministratori che gestiscono la distribuzione. L'estensione di file è xbap (per le applicazioni browser XAML (XBAPs) e .application per le applicazioni installate. Il primo è determinato dalla proprietà del HostInBrowser progetto e di conseguenza il manifesto identifica l'applicazione come ospitata nel browser.

Il manifesto dell'applicazione (un file manifesto .exe) descrive gli assembly dell'applicazione e le librerie dipendenti ed elenca le autorizzazioni richieste dall'applicazione. Questo file deve essere creato dallo sviluppatore dell'applicazione. Per avviare un'applicazione ClickOnce, un utente apre il file manifesto della distribuzione dell'applicazione.

Questi file manifesto vengono sempre creati per gli XBAP. Per le applicazioni installate, non vengono create a meno che la GenerateManifests proprietà non sia specificata nel file di progetto con valore true.

Gli XBAP ottengono due autorizzazioni aggiuntive oltre a quelle assegnate alle applicazioni tipiche dell'area Internet: WebBrowserPermission e MediaPermission. Il sistema di compilazione WPF dichiara tali autorizzazioni nel manifesto dell'applicazione.

Supporto per la compilazione incrementale

Il sistema di compilazione WPF fornisce il supporto per le compilazioni incrementali. È abbastanza intelligente per rilevare le modifiche apportate al markup o al codice e compila solo gli artefatti interessati dalla modifica. Il meccanismo di compilazione incrementale usa i file seguenti:

  • File $(AssemblyName)_MarkupCompiler.Cache per mantenere lo stato corrente del compilatore.

  • Un file $(AssemblyName)_MarkupCompiler.lref per memorizzare nella cache i file XAML con riferimenti a tipi definiti in locale.

Di seguito è riportato un set di regole che regolano la compilazione incrementale:

  • Il file è l'unità più piccola in cui il sistema di compilazione rileva la modifica. Pertanto, per un file di codice, il sistema di compilazione non può indicare se un tipo è stato modificato o se è stato aggiunto il codice. Lo stesso vale per i file di progetto.

  • Il meccanismo di compilazione incrementale deve essere consapevole del fatto che una pagina XAML definisce una classe o usa altre classi.

  • Se le voci Reference cambiano, ricompilare tutte le pagine.

  • Se un file di codice cambia, ricompilare tutte le pagine con riferimenti di tipo definiti in locale.

  • Se un file XAML cambia:

    • Se XAML viene dichiarato come Page nel progetto: se XAML non dispone di riferimenti di tipo definiti localmente, ricompilare il codice XAML più tutte le pagine XAML con riferimenti locali; se xaml include riferimenti locali, ricompilare tutte le pagine XAML con riferimenti locali.

    • Se XAML viene dichiarato come ApplicationDefinition nel progetto: ricompilare tutte le pagine XAML (motivo: ogni XAML ha riferimento a un Application tipo che potrebbe essere stato modificato).

  • Se il file di progetto dichiara un file di codice come definizione dell'applicazione anziché un file XAML:

    • Controllare se il ApplicationClassName valore nel file di progetto è stato modificato (è presente un nuovo tipo di applicazione?). In tal caso, ricompilare l'intera applicazione.

    • In caso contrario, ricompilare tutte le pagine XAML con riferimenti locali.

  • Se un file di progetto cambia: applicare tutte le regole precedenti e vedere cosa deve essere ricompilato. Le modifiche apportate alle proprietà seguenti attivano una ricompilazione completa: AssemblyName, IntermediateOutputPath, RootNamespacee HostInBrowser.

Sono possibili gli scenari di ricompilazione seguenti:

  • L'intera applicazione viene ricompilata.

  • Vengono ricompilati solo i file XAML con riferimenti di tipo definiti localmente.

  • Non viene ricompilato nulla (se non è stato modificato nulla nel progetto).

Vedere anche