Compartir a través de


Compilación de una aplicación WPF

Las aplicaciones de Windows Presentation Foundation (WPF) se pueden compilar como ejecutables de .NET Framework (.exe), bibliotecas (.dll) o una combinación de ambos tipos de ensamblados. En este tema se presenta cómo compilar aplicaciones WPF y se describen los pasos clave del proceso de compilación.

Creación de una aplicación WPF

Una aplicación WPF se puede compilar de las maneras siguientes:

Canalización de compilación de WPF

Cuando se compila un proyecto de WPF, se invoca la combinación de objetivos específicos del lenguaje y de WPF. El proceso de ejecución de estos objetivos se denomina pipeline de construcción, y la figura siguiente muestra los pasos clave.

Proceso de compilación de WPF

Inicializaciones previas a la construcción

Antes de compilar, MSBuild determina la ubicación de las herramientas y bibliotecas importantes, incluidas las siguientes:

  • The .NET Framework.

  • Directorios de Windows SDK.

  • Ubicación de los ensamblados de referencia de WPF.

  • Propiedad de las rutas de búsqueda de los ensamblados.

La primera ubicación donde MSBuild busca ensamblados es el directorio de ensamblado de referencia (%ProgramFiles%\Reference Assemblies\Microsoft\Framework\v3.0\). Durante este paso, el proceso de compilación también inicializa las distintas propiedades y grupos de elementos y realiza cualquier trabajo de limpieza necesario.

Resolución de referencias

El proceso de compilación busca y enlaza los ensamblados necesarios para compilar el proyecto de aplicación. Esta lógica está contenida en la ResolveAssemblyReference tarea. Todos los ensamblados declarados como Reference en el archivo del proyecto se proporcionan a la tarea junto con información sobre las rutas de búsqueda y los metadatos de los ensamblados ya instalados en el sistema. La tarea busca ensamblados y usa los metadatos del ensamblado instalado para filtrar los ensamblados principales de WPF que no necesitan aparecer en los manifiestos de salida. Esto se hace para evitar información redundante en los manifiestos ClickOnce. Por ejemplo, dado que PresentationFramework.dll se puede considerar representativo de una aplicación basada en y para WPF, y dado que todos los ensamblados de WPF existen en la misma ubicación en cada máquina que tenga instalado .NET Framework, no es necesario incluir toda la información sobre todos los ensamblados de referencia de .NET Framework en los manifiestos.

Compilación de marcado: paso 1

En este paso, los archivos XAML se analizan y compilan para que el tiempo de ejecución no dedique tiempo a analizar XML y validar los valores de propiedad. El archivo XAML compilado está previamente tokenizado para que, en tiempo de ejecución, cargarlo debería ser mucho más rápido que cargar un archivo XAML.

Durante este paso, se realizan las siguientes actividades para cada archivo XAML que sea un Page elemento de compilación:

  1. El compilador de marcado analiza el archivo XAML.

  2. Se crea una representación compilada para ese XAML y se copia en la carpeta obj\Release.

  3. Se crea una representación CodeDOM de una nueva clase parcial y se copia en la carpeta obj\Release.

Además, se genera un archivo de código específico del lenguaje para cada archivo XAML. Por ejemplo, para una página Page1.xaml en un proyecto de Visual Basic, se genera un Page1.g.vb; para una página Page1.xaml en un proyecto de C#, se genera un Page1.g.cs. El ".g" del nombre de archivo indica que el archivo se genera código que tiene una declaración de clase parcial para el elemento de nivel superior del archivo de marcado (como Page o Window). La clase se declara con el partial modificador en C# (Extends en Visual Basic) para indicar que hay otra declaración para la clase en otro lugar, normalmente en el archivo de código subyacente Page1.xaml.cs.

La clase parcial se extiende desde la clase base adecuada (por ejemplo Page , para una página) e implementa la System.Windows.Markup.IComponentConnector interfaz . La IComponentConnector interfaz tiene métodos para inicializar un componente y conectar nombres y eventos en elementos de su contenido. Por lo tanto, el archivo de código generado tiene una implementación de método como la siguiente:

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

De forma predeterminada, la compilación de marcado se ejecuta en el mismo AppDomain que el motor de MSBuild. Esto proporciona importantes mejoras de rendimiento. Este comportamiento se puede alternar con la propiedad AlwaysCompileMarkupFilesInSeparateDomain. Esto tiene la ventaja de liberar todos los ensamblados de referencia al desactivar el conjunto separado AppDomain.

Compilación de marcado: paso 2

No todas las páginas XAML se compilan durante el paso 1 de la compilación de marcado. Los archivos XAML que tienen referencias de tipo definidas localmente (referencias a tipos definidos en código en otro lugar del mismo proyecto) están exentos de la compilación en este momento. Esto se debe a que esos tipos definidos localmente solo existen en el origen y aún no se han compilado. Para determinar esto, el analizador usa heurística que implica buscar elementos como x:Name en el archivo de marcado. Cuando se encuentra una instancia de este tipo, la compilación del archivo de marcado se pospone hasta que se hayan compilado los archivos de código, tras lo cual la segunda pasada de compilación de marcado procesa estos archivos.

Clasificación de archivos

El proceso de compilación coloca los archivos de salida en diferentes grupos de recursos en función del ensamblado de aplicación en el que se colocarán. En una aplicación típica no localizada, todos los archivos de datos marcados como Resource se colocan en el ensamblado principal (ejecutable o biblioteca). Cuando UICulture se establece en el proyecto, todos los archivos XAML compilados y esos recursos marcados específicamente como específicos del lenguaje se colocan en el ensamblado de recursos satélite. Además, todos los recursos neutros de idioma se colocan en el ensamblado principal. En este paso del proceso de construcción, se realiza esa decisión.

Las acciones de generación ApplicationDefinition, Page y Resource del archivo del proyecto se pueden aumentar con los metadatos (valores aceptables son Localizable, true y false), lo que determina si el archivo es específico del lenguaje o independiente del lenguaje.

Compilación principal

El paso de compilación principal implica la compilación de archivos de código. Esto se orquesta mediante lógica en los archivos de destinos específicos del lenguaje Microsoft.CSharp.targets y Microsoft.VisualBasic.targets. Si heurística ha determinado que un solo paso del compilador de marcado es suficiente, se genera el ensamblado principal. Sin embargo, si uno o varios archivos XAML del proyecto tienen referencias a tipos definidos localmente, se genera un archivo de .dll temporal para que los ensamblados finales de la aplicación se puedan crear después de completar el segundo paso de compilación de marcado.

Generación de manifiestos

Al final del proceso de compilación, después de que todos los ensamblados de la aplicación y los archivos de contenido estén listos, se generan los manifiestos ClickOnce de la aplicación.

El archivo de manifiesto de implementación describe el modelo de implementación: la versión actual, el comportamiento de actualización y la identidad del publicador junto con la firma digital. Este manifiesto está diseñado para ser creado por los administradores que controlan la implementación. La extensión de archivo es .xbap (para aplicaciones de explorador XAML (XBAPs)) y .application para aplicaciones instaladas. El primero lo dicta la propiedad del HostInBrowser proyecto y, como resultado, el manifiesto identifica la aplicación como hospedada en el explorador.

El manifiesto de aplicación (un archivo .manifest de .exe) describe los ensamblados de aplicación y las bibliotecas dependientes y enumera los permisos necesarios para la aplicación. Este archivo está diseñado para ser creado por el desarrollador de aplicaciones. Para iniciar una aplicación ClickOnce, un usuario abre el archivo de manifiesto de implementación de la aplicación.

Estos archivos de manifiesto siempre se crean para XBAP. En el caso de las aplicaciones instaladas, no se crean a menos que se especifique la GenerateManifests propiedad en el archivo de proyecto con el valor true.

XBAPs obtienen dos permisos adicionales además de esos permisos asignados a las aplicaciones típicas de la zona de Internet: WebBrowserPermission y MediaPermission. El sistema de compilación de WPF declara esos permisos en el manifiesto de aplicación.

Compatibilidad con la compilación incremental

El sistema de compilación de WPF proporciona compatibilidad con compilaciones incrementales. Es bastante inteligente al detectar los cambios realizados en el marcado o el código, y solo compila aquellos artefactos afectados por el cambio. El mecanismo de compilación incremental usa los siguientes archivos:

  • Un archivo $(AssemblyName)_MarkupCompiler.Cache para mantener el estado actual del compilador.

  • Un archivo $(AssemblyName)_MarkupCompiler.lref para almacenar en caché los archivos XAML con referencias a tipos definidos localmente.

A continuación se muestra un conjunto de reglas que rigen la compilación incremental:

  • El archivo es la unidad más pequeña en la que el sistema de compilación detecta cambios. Por lo tanto, para un archivo de código, el sistema de compilación no puede indicar si se cambió un tipo o si se agregó código. Lo mismo se mantiene para los archivos de proyecto.

  • El mecanismo de compilación incremental debe ser consciente de que una página XAML define una clase o usa otras clases.

  • Si las entradas cambian, vuelva a compilar todas las páginas.

  • Si cambia un archivo de código, vuelva a compilar todas las páginas con referencias de tipo definidas localmente.

  • Si cambia un archivo XAML:

    • Si XAML se declara como Page en el proyecto: si el XAML no tiene referencias de tipo definidas localmente, vuelva a compilar ese XAML más todas las páginas XAML con referencias locales; si el XAML tiene referencias locales, vuelva a compilar todas las páginas XAML con referencias locales.

    • Si XAML se declara como ApplicationDefinition en el proyecto: vuelva a compilar todas las páginas XAML (motivo: cada XAML tiene referencia a un Application tipo que puede haber cambiado).

  • Si el archivo de proyecto declara un archivo de código como definición de aplicación en lugar de un archivo XAML:

    • Compruebe si el ApplicationClassName valor del archivo del proyecto ha cambiado (¿hay un nuevo tipo de aplicación?). Si es así, vuelva a compilar toda la aplicación.

    • De lo contrario, vuelva a compilar todas las páginas XAML con referencias locales.

  • Si un archivo de proyecto cambia: aplique todas las reglas anteriores y vea lo que debe volver a compilarse. Los cambios realizados en las siguientes propiedades desencadenan una recompilación completa: AssemblyName, IntermediateOutputPath, RootNamespacey HostInBrowser.

Los siguientes escenarios de recompilación son posibles:

  • Se vuelve a compilar toda la aplicación.

  • Solo se vuelven a compilar los archivos XAML que tienen referencias de tipo definidas localmente.

  • No se vuelve a compilar nada (si no ha cambiado nada en el proyecto).

Consulte también