Compilar um aplicativo WPF
Os aplicativos do WPF (Windows Presentation Foundation) podem ser criados como executáveis do .NET Framework (.exe), bibliotecas (.dll) ou uma combinação de ambos os tipos de assemblies. Este tópico apresenta como criar aplicativos WPF e descreve as principais etapas no processo de build.
Criando um aplicativo WPF
Um aplicativo WPF pode ser compilado das seguintes maneiras:
Linha de comando. O aplicativo deve conter apenas código (sem XAML) e um arquivo de definição de aplicativo. Para obter mais informações, consulte Build pela linha de comando com csc.exe ou Build na linha de comando (Visual Basic).
Microsoft Build Engine (MSBuild). Além do código e dos arquivos XAML, o aplicativo deve conter um arquivo de projeto do MSBuild. Para obter mais informações, consulte "MSBuild".
Visual Studio. O Visual Studio é um ambiente de desenvolvimento integrado que compila aplicativos WPF com o MSBuild e inclui um designer visual para criar a interface do usuário. Para obter mais informações, consulte Escrever e gerenciar código usando o Visual Studio e Design XAML no Visual Studio.
Pipeline de build do WPF
Quando um projeto WPF é compilado, a combinação de destinos específicos a um idioma e específicos do WPF é invocada. O processo de execução desses destinos denomina-se pipeline de build, e as principais etapas estão ilustradas na figura a seguir.
Inicializações pré-build
Antes de compilar, o MSBuild determina a localização de ferramentas e bibliotecas importantes, incluindo o seguinte:
O .NET Framework.
Os diretórios do SDK do Windows.
O local dos assemblies de referência do WPF.
A propriedade para os caminhos de pesquisa de assembly.
O primeiro local em que o MSBuild procura por assemblies é o diretório de assemblies de referência (%ProgramFiles%\Assemblies de referência\Microsoft\Framework\v3.0\). Durante essa etapa, o processo de build também inicializa as várias propriedades e grupos de itens e executa qualquer trabalho de limpeza necessário.
Resolvendo referências
O processo de build localiza e associa os assemblies necessários para criar o projeto de aplicativo. Essa lógica está contida na tarefa ResolveAssemblyReference
. Todos os assemblies declarados como Reference
no arquivo de projeto são fornecidos para a tarefa, junto com as informações sobre os caminhos de pesquisa e metadados sobre os assemblies já instalados no sistema. A tarefa procura assemblies e usa os metadados do assembly instalado para filtrar os principais assemblies do WPF que não precisam aparecer nos manifestos de saída. Isso é feito para evitar informações redundantes nos manifestos do ClickOnce. Por exemplo, como PresentationFramework.dll pode ser considerada representativa de um aplicativo criado e para WPF, e como todos os assemblies do WPF existem no mesmo local em cada computador que tenha o .NET Framework instalado, não é necessário incluir todas as informações em todos os assemblies de referência do .NET Framework nos manifestos.
Compilação de marcação — passo 1
Nesta etapa, os arquivos XAML são analisados e compilados para que o runtime não gaste tempo analisando XML e validando valores de propriedade. O arquivo XAML compilado é pré-tokenizado para que, em tempo de execução, carregá-lo seja muito mais rápido do que carregar um arquivo XAML.
Durante esta etapa, as seguintes atividades ocorrem para cada arquivo XAML que é um item de build Page
:
O arquivo XAML é analisado pelo compilador de marcação.
Uma representação compilada é criada para esse XAML e copiada para a pasta obj\Release.
Uma representação CodeDOM de uma nova classe parcial é criada e copiada para a pasta obj\Release.
Além disso, um arquivo de código específico do idioma é gerado para cada arquivo XAML. Por exemplo, para uma página Page1.xaml em um projeto do Visual Basic, um Page1.g.vb é gerado; para uma página Page1.xaml em um projeto C#, um Page1.g.cs é gerado. O ".g" no nome do arquivo indica que o arquivo é um código gerado que tem uma declaração de classe parcial para o elemento de nível superior do arquivo de marcação (como Page
ou Window
). A classe é declarada com o modificador partial
em C# (Extends
no Visual Basic) para indicar que há outra declaração para a classe em outro lugar, geralmente no arquivo code-behind Page1.xaml.cs.
A classe parcial se estende da classe base apropriada (como Page para uma página) e implementa a interface System.Windows.Markup.IComponentConnector. A interface IComponentConnector tem métodos para inicializar um componente e conectar nomes e eventos em elementos em seu conteúdo. Consequentemente, o arquivo de código gerado tem uma implementação de método como a seguinte:
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
Por padrão, a compilação de marcação é executada no mesmo AppDomain que o mecanismo MSBuild. Isso fornece ganhos de desempenho significativos. Esse comportamento pode ser alternado com a propriedade AlwaysCompileMarkupFilesInSeparateDomain
. Isso tem a vantagem de descarregar todos os assemblies de referência ao descarregar o AppDomain separadamente.
Compilação de marcação — passo 2
Nem todas as páginas XAML são compiladas na primeira passagem da compilação de marcação. Arquivos XAML que têm referências de tipo definidas localmente (referências a tipos definidos em código em outro lugar no mesmo projeto) estão isentos da compilação no momento. Isso ocorre porque esses tipos definidos localmente existem apenas na origem e ainda não foram compilados. Para determinar isso, o analisador usa heurísticas que envolvem procurar itens como x:Name
no arquivo de marcação. Quando essa instância é encontrada, a compilação desse arquivo de marcação é adiada até que os arquivos de código sejam compilados, após o que a segunda passagem de compilação de marcação processa esses arquivos.
Classificação de arquivo
O processo de build coloca arquivos de saída em diferentes grupos de recursos com base em qual assembly de aplicativo eles serão colocados. Em um aplicativo não localizado típico, todos os arquivos de dados marcados como Resource
são colocados no assembly principal (executável ou biblioteca). Quando a UICulture
é definida no projeto, todos os arquivos XAML compilados e os recursos especificamente marcados como específicos a um idioma, são colocados no assembly de recursos satélite. Além disso, todos os recursos neutros de idioma são colocados na assembléia principal. Nesta etapa do processo de build, essa determinação é feita.
As ações de compilação ApplicationDefinition
, Page
e Resource
no arquivo de projeto podem ser aumentadas com os metadados Localizable
(os valores aceitáveis são true
e false
), que determina se o arquivo é específico de linguagem ou neutro em idioma.
Compilação principal
A etapa de compilação principal envolve a compilação de arquivos de código. Isso é orquestrado por lógica nos arquivos de destinos específicos a um idioma Microsoft.CSharp.targets e Microsoft.VisualBasic.targets. Se as heurísticas determinarem que uma única passagem do compilador de marcação é suficiente, então o assembly principal será gerado. No entanto, se um ou mais arquivos XAML no projeto tiverem referências a tipos definidos localmente, um arquivo .dll temporário será gerado para que os assemblies finais do aplicativo possam ser criados após a conclusão da segunda passagem da compilação de marcação.
Geração de manifesto
Ao final do processo de build, quando todos os assemblies de aplicativo e arquivos de conteúdo estiverem prontos, os manifestos do ClickOnce para o aplicativo são gerados.
O arquivo de manifesto de implantação descreve o modelo de implantação: a versão atual, o comportamento da atualização e a identidade do editor, juntamente com a assinatura digital. Esse manifesto destina-se a ser criado por administradores que lidam com a implantação. A extensão de arquivo é .xbap (para XBAPs (aplicativos do navegador XAML)) e .application para aplicativos instalados. A primeira é determinada pela propriedade do projeto HostInBrowser
e, como resultado, o manifesto identifica o aplicativo como hospedado pelo navegador.
O manifesto do aplicativo (um arquivo .manifest .exe) descreve os assemblies do aplicativo e as bibliotecas dependentes e lista as permissões necessárias para o aplicativo. Esse arquivo destina-se a ser criado pelo desenvolvedor do aplicativo. Para iniciar um aplicativo ClickOnce, um usuário abre o arquivo de manifesto de implantação do aplicativo.
Esses arquivos de manifesto são sempre criados para XBAPs. Para aplicativos instalados, eles não são criados, a menos que a propriedade GenerateManifests
seja especificada no arquivo de projeto com o valor true
.
Os XBAPs obtêm duas permissões adicionais além dessas permissões atribuídas a aplicativos típicos de zona da Internet: WebBrowserPermission e MediaPermission. O sistema de build do WPF declara essas permissões no manifesto do aplicativo.
Suporte ao build incremental
O sistema de build do WPF fornece suporte para builds incrementais. É bastante inteligente detectar alterações feitas na marcação ou código e compila apenas os artefatos afetados pela alteração. O mecanismo de build incremental usa os seguintes arquivos:
Um arquivo $(AssemblyName)_MarkupCompiler.Cache para manter o estado atual do compilador.
Um arquivo $(AssemblyName)_MarkupCompiler.lref para armazenar em cache os arquivos XAML com referências a tipos definidos localmente.
Veja a seguir um conjunto de regras que regem o build incremental:
O arquivo é a menor unidade na qual o sistema de build detecta a alteração. Portanto, para um arquivo de código, o sistema de build não pode saber se um tipo foi alterado ou se o código foi adicionado. O mesmo vale para arquivos de projeto.
O mecanismo de build incremental deve estar ciente de que uma página XAML define uma classe ou usa outras classes.
Se as entradas
Reference
forem alteradas, recompile todas as páginas.Se um arquivo de código for alterado, recompile todas as páginas com referências de tipo definidas localmente.
Se um arquivo XAML for alterado:
Se XAML for declarado como
Page
no projeto: se o XAML não tiver referências de tipo definidas localmente, recompile esse XAML mais todas as páginas XAML com referências locais; se o XAML tiver referências locais, recompile todas as páginas XAML com referências locais.Se XAML for declarado como
ApplicationDefinition
no projeto: recompile todas as páginas XAML (motivo: cada XAML tem referência a um tipo de Application que pode ter sido alterado).
Se o arquivo de projeto declarar um arquivo de código como definição de aplicativo em vez de um arquivo XAML:
Verifique se o valor
ApplicationClassName
no arquivo de projeto foi alterado (há um novo tipo de aplicativo?). Nesse caso, recompile todo o aplicativo.Caso contrário, recompile todas as páginas XAML com referências locais.
Se um arquivo de projeto for alterado: aplique todas as regras anteriores e veja o que precisa ser recompilado. As alterações nas seguintes propriedades disparam um recompilamento completo:
AssemblyName
,IntermediateOutputPath
,RootNamespace
eHostInBrowser
.
Os seguintes cenários de recompilação são possíveis:
Todo o aplicativo é recompilado.
Somente os arquivos XAML que têm referências de tipo definidas localmente são recompilados.
Nada será recompilado (se nada no projeto tiver mudado).
Consulte também
.NET Desktop feedback