Visão geral do WPF

O Windows Presentation Foundation (WPF) permite criar aplicativos para cliente de área de trabalho do Windows com experiências de usuário visualmente impressionantes.

Contoso Healthcare UI sample

O núcleo do WPF é um mecanismo de renderização que não depende da resolução e baseado em vetor, criado para tirar proveito de hardwares gráficos modernos. O WPF estende o núcleo com um conjunto abrangente de funcionalidades de desenvolvimento de aplicativos que incluem linguagem XAML, controles, associação de dados, layout, elementos gráficos 2D e 3D, animação, estilos, modelos, documentos, mídia, texto e tipografia. O WPF faz parte do .NET; portanto, você pode criar aplicativos que incorporam outros elementos da API .NET.

Esta visão geral é destinada para principiantes e aborda os principais conceitos e funcionalidades do WPF.

Programar com o WPF

O WPF existe como um subconjunto de tipos .NET que (geralmente) estão localizados no namespace System.Windows. Se você tiver criado aplicativos com o .NET anteriormente usando tecnologias gerenciadas como ASP.NET e Windows Forms, a experiência essencial do WPF em programação deverá ser conhecida; você cria instâncias de classes, define propriedades, chama métodos e manipula eventos usando sua linguagem de programação .NET favorita como C# ou Visual Basic.

O WPF inclui constructos de programação adicionais que aprimoram as propriedades e eventos: propriedades de dependência e eventos roteados.

Marcação e code-behind

O WPF permite que você desenvolva um aplicativo usando marcação e code-behind, uma experiência com a qual os desenvolvedores do ASP.NET devem estar familiarizados. Você geralmente usa marcação XAML para implementar a aparência de um aplicativo enquanto usa linguagens de programação gerenciadas (code-behind) para implementar seu comportamento. Essa separação de aparência e comportamento apresenta os seguintes benefícios:

  • Custos de desenvolvimento e manutenção são reduzidos, pois a marcação específica da aparência não está acoplada ao comportamento específico do código.

  • O desenvolvimento é mais eficiente porque os designers podem implementar a aparência de um aplicativo simultaneamente com os desenvolvedores que estão implementando o comportamento do aplicativo.

  • A globalização e localização de aplicativos WPF é simplificada.

Marcação

O XAML é uma linguagem de marcação baseada em XML que implementa a aparência de um aplicativo de forma declarativa. Normalmente, ele é usado para criar janelas, caixas de diálogo, páginas e controles de usuário e para preenchê-los com controles, formas e elementos gráficos.

O exemplo a seguir usa XAML para implementar a aparência de uma janela que contém um único botão:

<Window
    xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
    Title="Window with Button"
    Width="250" Height="100">

  <!-- Add button to window -->
  <Button Name="button">Click Me!</Button>

</Window>

Especificamente, esse XAML define uma janela e um botão usando os elementos Window e Button, respectivamente. Cada elemento é configurado com atributos, como o atributo Title do elemento Window para especificar o texto da barra de título da janela. Em tempo de execução, o WPF converte os elementos e atributos que estão definidos na marcação para instâncias de classes do WPF. Por exemplo, o elemento Window é convertido em uma instância da classe Window, cuja propriedade Title é o valor do atributo Title.

A figura a seguir mostra a interface do usuário definida pelo XAML no exemplo anterior:

A window that contains a button

Já que o XAML é baseado em XML, a interface do usuário que você escreve com ele é montada em uma hierarquia de elementos aninhados conhecida como uma árvore de elementos. A árvore de elementos fornece uma maneira lógica e intuitiva para criar e gerenciar interfaces do usuário.

Code-behind

O comportamento principal de um aplicativo é implementar a funcionalidade que responde às interações do usuário, incluindo a manipulação de eventos (por exemplo, clicar em um menu, barra de ferramentas ou botão) e chamar a lógica de negócios e lógica de acesso a dados como resposta. No WPF, esse comportamento é implementado no código que está associado à marcação. Esse tipo de código é conhecido como code-behind. O exemplo a seguir mostra a marcação atualizada do exemplo anterior e o code-behind:

<Window
    xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
    xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
    x:Class="SDKSample.AWindow"
    Title="Window with Button"
    Width="250" Height="100">

  <!-- Add button to window -->
  <Button Name="button" Click="button_Click">Click Me!</Button>

</Window>
using System.Windows; // Window, RoutedEventArgs, MessageBox

namespace SDKSample
{
    public partial class AWindow : Window
    {
        public AWindow()
        {
            // InitializeComponent call is required to merge the UI
            // that is defined in markup with this class, including  
            // setting properties and registering event handlers
            InitializeComponent();
        }

        void button_Click(object sender, RoutedEventArgs e)
        {
            // Show message box when button is clicked.
            MessageBox.Show("Hello, Windows Presentation Foundation!");
        }
    }
}
Namespace SDKSample

    Partial Public Class AWindow
        Inherits System.Windows.Window

        Public Sub New()

            ' InitializeComponent call is required to merge the UI
            ' that is defined in markup with this class, including  
            ' setting properties and registering event handlers
            InitializeComponent()

        End Sub

        Private Sub button_Click(ByVal sender As Object, ByVal e As RoutedEventArgs)

            ' Show message box when button is clicked.
            MessageBox.Show("Hello, Windows Presentation Foundation!")

        End Sub

    End Class

End Namespace

Neste exemplo, o code-behind implementa uma classe derivada da classe Window. O atributo x:Class é usado para associar a marcação com a classe code-behind. InitializeComponent é chamado de construtor da classe code-behind para mesclar a interface do usuário que é definida na marcação com a classe code-behind. InitializeComponent( é gerado para você quando seu aplicativo é criado, e é por isso que você não precisa implementá-lo manualmente.) A combinação de x:Class e InitializeComponent garantir que sua implementação seja inicializada corretamente sempre que for criada. A classe code-behind também implementa um manipulador de eventos para o evento Click do botão. Quando o botão é clicado, o manipulador de eventos mostra uma caixa de mensagem ao chamar o método System.Windows.MessageBox.Show.

A figura a seguir mostra o resultado quando o botão é clicado:

A MessageBox

Controles

As experiências de usuário que são entregues pelo modelo de aplicativo são controles construídos. No WPF, controle é um termo abrangente que se aplica a uma categoria de classes do WPF que são hospedadas em uma janela ou uma página, que têm uma interface do usuário e que implementam um comportamento.

Para obter mais informações, consulte Controles.

Controles do WPF por função

Os controles internos do WPF estão listados aqui:

Entrada e comandos

Controles normalmente detectam e respondem a entradas do usuário. O sistema de entrada do WPF usa tanto os eventos diretos como os roteados para dar suporte a entrada de texto, foco de gerenciamento e posicionamento do mouse.

Aplicativos muitas vezes têm requisitos de entrada complexos. O WPF fornece um sistema de comando que separa as ações de entrada do usuário do código que responde a essas ações.

Layout

Quando você cria uma interface do usuário, você organiza os controles por local e tamanho para formar um layout. Um requisito chave de qualquer layout é se adaptar a alterações no tamanho da janela e exibir as configurações. Em vez de forçá-lo a escrever o código para adaptar um layout nessas circunstâncias, o WPF fornece um sistema de layout extensível e de primeira classe para você.

A base do sistema de layout é o posicionamento relativo, que aumenta a capacidade de se adaptar às modificações da janela e condições de exibição. Além disso, o sistema de layout gerencia a negociação entre os controles para determinar o layout. A negociação é um processo de duas etapas: primeiro, um controle informa ao pai o local e tamanho requerido; segundo, o pai informa ao controle qual espaço ele pode ter.

O sistema de layout é exposto aos controles filho por meio de classes base do WPF. Para layouts comuns, como grades, empilhamento e encaixe, o WPF inclui vários controles de layout:

  • Canvas: os controles filho fornecem seus próprios layouts.

  • DockPanel: os controles filho são alinhados com as bordas do painel.

  • Grid: os controles filho são posicionados por linhas e colunas.

  • StackPanel: os controles filho são empilhados verticalmente ou horizontalmente.

  • VirtualizingStackPanel: os controles filho são virtualizados e organizados em uma única linha, que é orientada horizontal ou verticalmente.

  • WrapPanel: os controles filho são posicionados na ordem da esquerda para a direita e, quando há mais controles na linha atual do que o espaço permite, sofrem quebra automática para a próxima linha.

O exemplo a seguir usa um DockPanel para definir vários controles de TextBox:

<Window
    xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
    xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
    x:Class="SDKSample.LayoutWindow"
    Title="Layout with the DockPanel" Height="143" Width="319">
  
  <!--DockPanel to layout four text boxes--> 
  <DockPanel>
    <TextBox DockPanel.Dock="Top">Dock = "Top"</TextBox>
    <TextBox DockPanel.Dock="Bottom">Dock = "Bottom"</TextBox>
    <TextBox DockPanel.Dock="Left">Dock = "Left"</TextBox>
    <TextBox Background="White">This TextBox "fills" the remaining space.</TextBox>
  </DockPanel>

</Window>

O DockPanel permite que os controles TextBox filho informem como organizá-los. Para fazer isso, o DockPanel implementa uma propriedade anexada Dock que é exposta aos controles filho para permitir que cada um especifique um estilo de encaixe.

Observação

Uma propriedade que é implementada por um controle pai para uso por controles filho é uma constructo do WPF chamado de propriedade anexada.

A figura a seguir mostra o resultado da marcação XAML no exemplo anterior:

DockPanel page

Vinculação de dados

A maioria dos aplicativos são criados para fornecer aos usuários os meios para exibir e editar dados. Para aplicativos WPF, o trabalho de armazenar e acessar dados já é fornecido por tecnologias, como SQL Server e ADO.NET. Depois que os dados são acessados e carregados em objetos gerenciados do aplicativo, começa o trabalho pesado para os aplicativos WPF. Essencialmente, isso envolve duas coisas:

  1. Copiar os dados dos objetos gerenciados para controles, nos quais os dados podem ser exibidos e editados.

  2. Assegurar que as alterações feitas nos dados usando controles sejam copiadas para os objetos gerenciados.

Para simplificar o desenvolvimento de aplicativos, o WPF fornece um mecanismo de vinculação de dados para executar essas etapas automaticamente. A unidade principal do mecanismo de associação de dados é a classe Binding, cujo trabalho é associar um controle (o destino da associação) a um objeto de dados (a origem da associação). Essa relação é ilustrada pela figura a seguir:

Basic data binding diagram

O exemplo a seguir demonstra como associar um TextBox a uma instância de um objeto Person personalizado. A implementação de Person é mostrada no código a seguir:

Namespace SDKSample

    Class Person

        Private _name As String = "No Name"

        Public Property Name() As String
            Get
                Return _name
            End Get
            Set(ByVal value As String)
                _name = value
            End Set
        End Property

    End Class

End Namespace
namespace SDKSample
{
    class Person
    {
        string name = "No Name";

        public string Name
        {
            get { return name; }
            set { name = value; }
        }
    }
}

A marcação a seguir vincula o a TextBox uma instância de um objeto personalizado Person :

 <Window
     xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
     xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
     x:Class="SDKSample.DataBindingWindow">

   <!-- Bind the TextBox to the data source (TextBox.Text to Person.Name) -->
   <TextBox Name="personNameTextBox" Text="{Binding Path=Name}" />

 </Window>
Imports System.Windows ' Window

Namespace SDKSample

    Partial Public Class DataBindingWindow
        Inherits Window

        Public Sub New()
            InitializeComponent()

            ' Create Person data source
            Dim person As Person = New Person()

            ' Make data source available for binding
            Me.DataContext = person

        End Sub

    End Class

End Namespace
using System.Windows; // Window

namespace SDKSample
{
    public partial class DataBindingWindow : Window
    {
        public DataBindingWindow()
        {
            InitializeComponent();

            // Create Person data source
            Person person = new Person();

            // Make data source available for binding
            this.DataContext = person;
        }
    }
}

Neste exemplo, a classe Person é instanciada no code-behind e é definida como o contexto de dados para o DataBindingWindow. Na marcação, a propriedade Text do TextBox está associada à propriedade Person.Name (usando a sintaxe XAML "{Binding ... }"). Esse XAML solicita que o WPF associe o controle TextBox ao objeto Person armazenado na propriedade DataContext da janela.

O mecanismo de vinculação de dados do WPF fornece suporte adicional que inclui a validação, classificação, filtragem e agrupamento. Além disso, a vinculação de dados dá suporte ao uso de modelos de dados para criar a interface do usuário personalizada para dados associados quando a interface do usuário exibida pelos controles WPF padrão não é apropriada.

Para obter mais informações, confira Visão geral de associação de dados.

Gráficos

O WPF introduz um conjunto amplo, escalonável e flexível de funcionalidades gráficas com os seguintes benefícios:

  • Elementos gráficos independentes de resolução e de dispositivo. A unidade básica de medida no sistema gráfico do WPF é o pixel independente de dispositivo, que é 1/96 de polegada, independentemente da resolução de tela e que fornece a base para a renderização independente de resolução e de dispositivo. Cada pixel independente de dispositivo pode ser dimensionado automaticamente para corresponder à configuração de dpi (pontos por polegada) do sistema em que ele é renderizado.

  • Maior precisão. O sistema de coordenadas do WPF é medido com números de ponto flutuante de precisão dupla em vez de precisão simples. Transformações e valores opacidade também são expressos com precisão dupla. O WPF também dá suporte a uma gama de cores (scRGB) e oferece suporte integrado para gerenciar entradas de diferentes espaços de cores.

  • Suporte a animação e elementos gráficos avançados. O WPF simplifica a programação de elementos gráficos ao gerenciar cenas de animação para você; não é necessário se preocupar sobre o processamento da cena, loops de renderização e interpolação bilinear. Além disso, o WPF dá suporte a teste de clique e suporte completo a composição alfa.

  • Aceleração de hardware. Sistema gráfico do WPF tira proveito do hardware gráfico para minimizar o uso da CPU.

Formas 2D

O WPF fornece uma biblioteca de formas vetoriais 2D comuns como retângulos e elipses, que são mostradas na ilustração a seguir:

Ellipses and rectangles

Uma funcionalidade interessante de formas é que elas não são apenas para exibição; as formas implementam muitas das funcionalidades que você espera dos controles, incluindo entrada de teclado e de mouse. O exemplo a seguir mostra o MouseUp evento de um Ellipse sendo manipulado:

<Window 
    xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
    xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
    x:Class="SDKSample.EllipseEventHandlingWindow"
    Title="Click the Ellipse">
    <Ellipse Name="clickableEllipse" Fill="Blue" MouseUp="clickableEllipse_MouseUp" />
</Window>
Imports System.Windows ' Window, MessageBox
Imports System.Windows.Input ' MouseButtonEventArgs

Namespace SDKSample

    Public Class EllipseEventHandlingWindow
        Inherits Window

        Public Sub New()
            InitializeComponent()
        End Sub

        Private Sub clickableEllipse_MouseUp(ByVal sender As Object, ByVal e As MouseButtonEventArgs)
            MessageBox.Show("You clicked the ellipse!")
        End Sub

    End Class

End Namespace
using System.Windows; // Window, MessageBox
using System.Windows.Input; // MouseButtonEventHandler

namespace SDKSample
{
    public partial class EllipseEventHandlingWindow : Window
    {
        public EllipseEventHandlingWindow()
        {
            InitializeComponent();
        }

        void clickableEllipse_MouseUp(object sender, MouseButtonEventArgs e)
        {
            // Display a message
            MessageBox.Show("You clicked the ellipse!");
        }
    }
}

A figura a seguir mostra o que é produzido pelo código anterior:

A window with the text

Para obter mais informações, confira Visão geral de formas e desenho básico no WPF.

Geometrias 2D

As formas 2D fornecidas pelo WPF abrangem o conjunto padrão de formas básicas. No entanto, talvez seja necessário criar formas personalizadas para facilitar o design de uma interface do usuário personalizada. Para essa finalidade, o WPF fornece geometrias. A figura a seguir demonstra o uso de geometrias para criar uma forma personalizada que pode ser desenhada diretamente, usada como um pincel ou usada para recortar outras formas e controles.

Os objetos Path podem ser usados para desenhar formas fechadas ou abertas, várias formas e até mesmo formas curvas.

Os objetos Geometry podem ser usados para recorte, teste de clique e renderização de dados gráficos 2D.

Various uses of a path

Para obter mais informações, confira Visão geral de geometria.

Efeitos 2D

Um subconjunto de funcionalidades 2D do WPF inclui efeitos visuais como gradientes, bitmaps, desenhos, pintura com vídeos, rotação, dimensionamento e distorção. Tudo isso é conseguido com pincéis; A figura a seguir mostra alguns exemplos:

Illustration of different brushes

Para obter mais informações, confira Visão geral de pincéis do WPF.

Renderização 3D

O WPF também inclui recursos de renderização 3D que se integram a elementos gráficos 2D para permitir a criação de interfaces de usuário mais interessantes e interessantes. Por exemplo, a figura a seguir mostra imagens 2D renderizadas em formas 3D:

Visual3D sample screen shot

Para obter mais informações, confira Visão geral de elementos gráficos 3D.

Animação

O suporte a animação do WPF permite que você faça os controles crescerem, tremerem, rodarem e esmaecerem, para criar transições de página interessantes e muito mais. Você pode animar a maioria das classes do WPF, até mesmo classes personalizadas. A figura a seguir mostra uma animação simples em ação:

Images of an animated cube

Para obter mais informações, confira Visão geral de animação.

Mídia

Uma maneira de transmitir conteúdo rico é pelo uso de mídia audiovisual. O WPF dá suporte especial para imagens, áudio e vídeo.

Imagens

Imagens são comuns à maioria dos aplicativos e o WPF fornece várias maneiras de usá-las. A figura a seguir mostra uma interface do usuário com uma caixa de listagem que contém imagens em miniatura. Quando uma miniatura é selecionada, a imagem é mostrada em tamanho normal.

Thumbnail images and a full-size image

Para obter mais informações, confira Visão geral de geração de imagens.

Áudio e vídeo

O controle MediaElement é capaz de executar áudio e vídeo e é flexível o suficiente para ser a base de um player de mídia personalizado. A marcação XAML a seguir implementa um media player:

<MediaElement 
  Name="myMediaElement" 
  Source="media/wpf.wmv" 
  LoadedBehavior="Manual" 
  Width="350" Height="250" />

A janela na figura a seguir mostra o MediaElement controle em ação:

A MediaElement control with audio and video

Para obter mais informações, confira Elementos gráficos e multimídia.

Texto e tipografia

Para facilitar a renderização de texto de alta qualidade, o WPF oferece as seguintes funcionalidades:

  • Suporte a fontes OpenType.

  • Aprimoramentos de ClearType.

  • Alto desempenho que tira proveito da aceleração de hardware.

  • Integração do texto com mídia, elementos gráficos e animação.

  • Mecanismos de fallback e suporte a fontes internacionais.

Como demonstração de integração de texto com elementos gráficos, a figura a seguir mostra a aplicação de decorações de texto:

Text with various text decorations

Para obter mais informações, consulte Tipografia na Windows Presentation Foundation.

Personalizar aplicativos do WPF

Até aqui, você viu os principais blocos de construção do WPF principal para o desenvolvimento de aplicativos. Você pode usar o modelo de aplicativo para hospedar e entregar conteúdo do aplicativo, que consiste principalmente de controles. Para simplificar a organização dos controles em uma interface do usuário e assegurar que a organização seja mantida em caso de alterações no tamanho da janela e configurações de exibição, você deverá usar o sistema de layout do WPF. Já que a maioria dos aplicativos permite aos usuários interagir com os dados, use a associação de dados para reduzir o trabalho de integração da interface do usuário com os dados. Para melhorar a aparência visual do seu aplicativo, você deve usar a ampla gama de suporte a elementos gráficos, animação e mídia fornecido pelo WPF.

Muitas vezes, no entanto, os conceitos básicos não são suficientes para criar e gerenciar uma experiência do usuário realmente distinta e visualmente impressionante. Os controles padrão do WPF podem não ser integrados à aparência desejada do aplicativo. Os dados podem não ser exibidos da maneira mais eficiente. A experiência do usuário geral do seu aplicativo pode não ser adequada para a aparência padrão de temas do Windows. Em muitos aspectos, uma tecnologia de apresentação precisa de extensibilidade visual, assim como qualquer outro tipo de extensibilidade.

Por esse motivo, o WPF fornece uma variedade de mecanismos para criar experiências de usuário exclusivas, incluindo um modelo rico de conteúdo para controles, gatilhos, modelos de dados e de controle, estilos, recursos de interface do usuário, temas e capas.

Modelo de conteúdo

O principal objetivo da maioria dos controles WPF é exibir conteúdo. No WPF, o tipo e o número de itens que podem constituir o conteúdo de um controle são conhecidos como o modelo de conteúdo do controle. Alguns controles podem conter um único item e o tipo de conteúdo. Por exemplo, o conteúdo de um TextBox é um valor de cadeia de caracteres que é atribuído à propriedade Text. O exemplo a seguir define o conteúdo de um TextBox:

<Window
    xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
    xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
    x:Class="SDKSample.TextBoxContentWindow"
    Title="TextBox Content">

    <TextBox Text="This is the content of a TextBox." />
</Window>

A figura a seguir mostra o resultado:

A TextBox control that contains text

Outros controles, entretanto, podem conter vários itens de diferentes tipos de conteúdo. O conteúdo de um Button, especificado pela propriedade Content, pode conter uma variedade de itens, incluindo controles de layout, texto, imagens e formas. O exemplo a seguir mostra um com conteúdo que inclui um , a , a Labele um MediaElementButtonDockPanel:Border

<Window
    xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
    xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
    x:Class="SDKSample.ButtonContentWindow"
    Title="Button Content">

  <Button Margin="20">
    <!-- Button Content -->
    <DockPanel Width="200" Height="180">
      <Label DockPanel.Dock="Top" HorizontalAlignment="Center">Click Me!</Label>
      <Border Background="Black" BorderBrush="Yellow" BorderThickness="2"
        CornerRadius="2" Margin="5">
        <MediaElement Source="media/wpf.wmv" Stretch="Fill" />
      </Border>
    </DockPanel>
  </Button>
</Window>

A figura a seguir mostra o conteúdo desse botão:

A button that contains multiple types of content

Para obter mais informações sobre os tipos de conteúdo compatíveis com vários controles, confira Modelo de conteúdo do WPF.

Gatilhos

Embora o objetivo principal da marcação XAML seja implementar a aparência de um aplicativo, você também pode usar XAML para implementar alguns aspectos do comportamento do aplicativo. Um exemplo é o uso de gatilhos para alterar a aparência de um aplicativo com base em interações do usuário. Para obter mais informações, confira Estilos e modelos.

Modelos de controle

As interfaces do usuário padrão para controles WPF normalmente são construídas de outros controles e formas. Por exemplo, um Button é composto de dois controles, ButtonChrome e ContentPresenter. O ButtonChrome fornece a aparência padrão do botão, enquanto o ContentPresenter exibe o conteúdo do botão, conforme especificado pela propriedade Content.

Às vezes, a aparência padrão de um controle pode ser incongruente com a aparência geral de um aplicativo. Nesse caso, você pode usar um ControlTemplate para alterar a aparência da interface do usuário do controle sem alterar seu conteúdo e seu comportamento.

O exemplo a seguir mostra como alterar a aparência de um usando um ButtonControlTemplate:

<Window 
  xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
  xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
  x:Class="SDKSample.ControlTemplateButtonWindow"
  Title="Button with Control Template" Height="158" Width="290">

  <!-- Button using an ellipse -->
  <Button Content="Click Me!" Click="button_Click">
    <Button.Template>
      <ControlTemplate TargetType="{x:Type Button}">
        <Grid Margin="5">
          <Ellipse Stroke="DarkBlue" StrokeThickness="2">
            <Ellipse.Fill>
              <RadialGradientBrush Center="0.3,0.2" RadiusX="0.5" RadiusY="0.5">
                <GradientStop Color="Azure" Offset="0.1" />
                <GradientStop Color="CornflowerBlue" Offset="1.1" />
              </RadialGradientBrush>
            </Ellipse.Fill>
          </Ellipse>
          <ContentPresenter Name="content" HorizontalAlignment="Center" 
            VerticalAlignment="Center"/>
        </Grid>
      </ControlTemplate>
    </Button.Template>

  </Button>

</Window>
using System.Windows; // Window, RoutedEventArgs, MessageBox

namespace SDKSample
{
    public partial class ControlTemplateButtonWindow : Window
    {
        public ControlTemplateButtonWindow()
        {
            InitializeComponent();
        }

        void button_Click(object sender, RoutedEventArgs e)
        {
            // Show message box when button is clicked
            MessageBox.Show("Hello, Windows Presentation Foundation!");
        }
    }
}
Imports System.Windows ' Window, RoutedEventArgs, MessageBox

Namespace SDKSample

    Public Class ControlTemplateButtonWindow
        Inherits Window

        Public Sub New()

            InitializeComponent()

        End Sub

        Private Sub button_Click(ByVal sender As Object, ByVal e As RoutedEventArgs)
            MessageBox.Show("Hello, Windows Presentation Foundation!")
        End Sub

    End Class

End Namespace

Neste exemplo, a interface do usuário padrão do botão foi substituída por um Ellipse que tem uma borda azul-escuro e foi preenchido usando um RadialGradientBrush. O ContentPresenter controle exibe o conteúdo do Button, "Clique em mim!" Quando o é clicado, o ButtonClick evento ainda é gerado como parte do comportamento padrão do Button controle. O resultado é mostrado na figura a seguir:

An elliptical button and a second window

Modelos de dados

Enquanto um modelo de controle permite que você especifique a aparência de um controle, um modelo de dados permite que você especifique a aparência do conteúdo de um controle. Modelos de dados são frequentemente usados para aprimorar o modo como os dados associados são exibidos. A figura a seguir mostra a aparência padrão de um ListBox associado a uma coleção de objetos Task, em que cada tarefa tem um nome, uma descrição e uma prioridade:

A list box with the default appearance

A aparência padrão é o que seria esperado de ListBox. No entanto, a aparência padrão de cada tarefa contém somente o nome da tarefa. Para mostrar o nome da tarefa, a descrição e a prioridade, a aparência padrão dos itens da lista associada ao controle ListBox deve ser alterada usando um DataTemplate. O XAML a seguir define tal , DataTemplateque é aplicado a cada tarefa usando o ItemTemplate atributo:

<Window
  xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
  xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
  x:Class="SDKSample.DataTemplateWindow"
  Title="With a Data Template">
  <Window.Resources>
    <!-- Data Template (applied to each bound task item in the task collection) -->
    <DataTemplate x:Key="myTaskTemplate">
      <Border Name="border" BorderBrush="DarkSlateBlue" BorderThickness="2"
        CornerRadius="2" Padding="5" Margin="5">
        <Grid>
          <Grid.RowDefinitions>
            <RowDefinition/>
            <RowDefinition/>
            <RowDefinition/>
          </Grid.RowDefinitions>
          <Grid.ColumnDefinitions>
            <ColumnDefinition Width="Auto" />
            <ColumnDefinition />
          </Grid.ColumnDefinitions>
          <TextBlock Grid.Row="0" Grid.Column="0" Padding="0,0,5,0" Text="Task Name:"/>
          <TextBlock Grid.Row="0" Grid.Column="1" Text="{Binding Path=TaskName}"/>
          <TextBlock Grid.Row="1" Grid.Column="0" Padding="0,0,5,0" Text="Description:"/>
          <TextBlock Grid.Row="1" Grid.Column="1" Text="{Binding Path=Description}"/>
          <TextBlock Grid.Row="2" Grid.Column="0" Padding="0,0,5,0" Text="Priority:"/>
          <TextBlock Grid.Row="2" Grid.Column="1" Text="{Binding Path=Priority}"/>
        </Grid>
      </Border>
    </DataTemplate>
  </Window.Resources>

  <!-- UI -->
  <DockPanel>
    <!-- Title -->
    <Label DockPanel.Dock="Top" FontSize="18" Margin="5" Content="My Task List:"/>

    <!-- Data template is specified by the ItemTemplate attribute -->
    <ListBox
      ItemsSource="{Binding}"
      ItemTemplate="{StaticResource myTaskTemplate}"
      HorizontalContentAlignment="Stretch"
      IsSynchronizedWithCurrentItem="True"
      Margin="5,0,5,5" />

 </DockPanel>
</Window>

A figura a seguir mostra o efeito desse código:

List box that uses a data template

Observe que o ListBox manteve seu comportamento e sua aparência geral. Apenas a aparência do conteúdo que está sendo exibido pela caixa de listagem foi alterada.

Para obter mais informações, confira Visão geral de modelagem de dados.

Estilos

Os estilos permitem que os desenvolvedores e designers padronizem uma determinada aparência para seus produtos. O WPF fornece um modelo de estilo sólido, cuja base é o elemento Style. O exemplo a seguir cria um estilo que define a cor do plano de fundo para cada Button em uma janela como Orange:

<Window
    xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
    xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
    x:Class="SDKSample.StyleWindow"
    Title="Styles">
    
    <Window.Resources>
        <!-- Style that will be applied to all buttons for this window -->
        <Style TargetType="{x:Type Button}">
            <Setter Property="Background" Value="Orange" />
            <Setter Property="BorderBrush" Value="Crimson" />
            <Setter Property="FontSize" Value="20" />
            <Setter Property="FontWeight" Value="Bold" />
            <Setter Property="Margin" Value="5" />
        </Style>
    </Window.Resources>
    <StackPanel>

        <!-- This button will have the style applied to it -->
        <Button>Click Me!</Button>

        <!-- This label will not have the style applied to it -->
        <Label>Don't Click Me!</Label>

        <!-- This button will have the style applied to it -->
        <Button>Click Me!</Button>
        
    </StackPanel>
</Window>

Já que esse estilo atinge todos os controles Button, o estilo é aplicado automaticamente a todos os botões na janela, conforme mostrado na figura a seguir:

Two orange buttons

Para obter mais informações, confira Estilos e modelos.

Recursos

Controles em um aplicativo devem compartilhar a mesma aparência, que pode incluir qualquer coisa de fontes e cores da tela de fundo até estilos, modelos de dados e modelos de controle. Você pode usar o suporte do WPF para recursos de interface do usuário para encapsular esses recursos em um único local para reutilização.

O exemplo a seguir define uma cor de plano de fundo comum compartilhada por um Button e um Label:

<Window
    xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
    xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
    x:Class="SDKSample.ResourcesWindow"
    Title="Resources Window">

  <!-- Define window-scoped background color resource -->
  <Window.Resources>
    <SolidColorBrush x:Key="defaultBackground" Color="Red" />
  </Window.Resources>

  <!-- Button background is defined by window-scoped resource -->
  <Button Background="{StaticResource defaultBackground}">One Button</Button>

  <!-- Label background is defined by window-scoped resource -->
  <Label Background="{StaticResource defaultBackground}">One Label</Label>
</Window>

Este exemplo implementa um recurso de cor da tela de fundo usando o elemento da propriedade Window.Resources. Este recurso está disponível para todos os filhos de Window. Há uma variedade de recursos escopos, incluindo os seguintes, listados na ordem em que eles são resolvidos:

  1. Um controle individual (usando a propriedade System.Windows.FrameworkElement.Resources herdada).

  2. Um Window ou um Page (também usando a propriedade herdada System.Windows.FrameworkElement.Resources).

  3. Um Application (usando a propriedade System.Windows.Application.Resources).

A variedade de escopos oferece flexibilidade em relação à maneira na qual você pode definir e compartilhar seus recursos.

Como uma alternativa a associar diretamente os recursos a um escopo específico, você pode compactar um ou mais recursos usando um ResourceDictionary separado, que pode ser referenciado em outras partes de um aplicativo. Por exemplo, o exemplo a seguir define uma cor de plano de fundo padrão em um dicionário de recursos:

<ResourceDictionary
    xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
    xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml">

  <!-- Define background color resource -->
  <SolidColorBrush x:Key="defaultBackground" Color="Red" />

  <!-- Define other resources -->
</ResourceDictionary>

O exemplo a seguir faz referência ao dicionário de recursos definido no exemplo anterior para que ele seja compartilhado em um aplicativo:

<Application
    xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
    xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
    x:Class="SDKSample.App">

  <Application.Resources>
    <ResourceDictionary>
      <ResourceDictionary.MergedDictionaries>
        <ResourceDictionary Source="BackgroundColorResources.xaml"/>
      </ResourceDictionary.MergedDictionaries>
    </ResourceDictionary>
  </Application.Resources>
</Application>

Recursos e dicionários de recurso são a base do suporte do WPF a temas e capas.

Para saber mais, confira Recursos.

Controles personalizados

Embora o WPF forneça um host de suporte a personalização, você poderá encontrar situações em que os controles WPF existentes não atendam às necessidades de seu aplicativo ou seus usuários. Isso pode ocorrer quando:

  • Não é possível criar a interface do usuário que você precisa ao personalizar a aparência de implementações existentes do WPF.

  • Não há suporte para o comportamento que você precisa (ou não é um suporte obtido facilmente) por implementações existentes do WPF.

Neste ponto, no entanto, você pode tirar proveito de um dos três modelos do WPF para criar um novo controle. Cada modelo destina-se a um cenário específico e requer que o controle personalizado derive de uma classe base específica do WPF. Os três modelos estão listados aqui:

  • Modelo de Controle de Usuário. Um controle personalizado é derivado de UserControl e é composto de um ou mais controles.

  • Modelo de Controle. Um controle personalizado é derivado de Control e é usado para criar implementações que separam seu comportamento de sua aparência usando modelos, como a maioria dos controles do WPF. Derivar de Control proporciona mais liberdade para criar uma interface do usuário personalizada de controles de usuário, mas pode exigir mais esforço.

  • Modelo de elemento de estrutura. Um controle personalizado é derivado de FrameworkElement quando sua aparência é definida pela lógica de renderização personalizada (e não por modelos).

O exemplo a seguir mostra um controle numérico personalizado para cima/para baixo que deriva de UserControl:

<UserControl
  xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
  xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
  x:Class="SDKSample.NumericUpDown">

  <Grid>

    <Grid.RowDefinitions>
      <RowDefinition/>
      <RowDefinition/>
    </Grid.RowDefinitions>
    <Grid.ColumnDefinitions>
      <ColumnDefinition/>
      <ColumnDefinition/>
    </Grid.ColumnDefinitions>

    <!-- Value text box -->
    <Border BorderThickness="1" BorderBrush="Gray" Margin="2" Grid.RowSpan="2" 
      VerticalAlignment="Center" HorizontalAlignment="Stretch">
      <TextBlock Name="valueText" Width="60" TextAlignment="Right" Padding="5"/>
    </Border>

    <!-- Up/Down buttons -->
    <RepeatButton Name="upButton" Click="upButton_Click" Grid.Column="1" 
      Grid.Row="0">Up</RepeatButton>
    <RepeatButton Name="downButton" Click="downButton_Click" Grid.Column="1" 
      Grid.Row="1">Down</RepeatButton>

  </Grid>

</UserControl>
using System; // EventArgs
using System.Windows; // DependencyObject, DependencyPropertyChangedEventArgs,
                      // FrameworkPropertyMetadata, PropertyChangedCallback,
                      // RoutedPropertyChangedEventArgs
using System.Windows.Controls; // UserControl

namespace SDKSample
{
    public partial class NumericUpDown : UserControl
    {
        // NumericUpDown user control implementation
    }
}
imports System 'EventArgs
imports System.Windows 'DependencyObject, DependencyPropertyChangedEventArgs, 
                       ' FrameworkPropertyMetadata, PropertyChangedCallback, 
                       ' RoutedPropertyChangedEventArgs
imports System.Windows.Controls 'UserControl

Namespace SDKSample

    ' Interaction logic for NumericUpDown.xaml
    Partial Public Class NumericUpDown
        Inherits System.Windows.Controls.UserControl

        'NumericUpDown user control implementation

    End Class

End Namespace

O exemplo a seguir ilustra o XAML necessário para incorporar o controle de usuário em um Window:

<Window
    xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
    xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
    x:Class="SDKSample.UserControlWindow"
    xmlns:local="clr-namespace:SDKSample" 
    Title="User Control Window">

  <!-- Numeric Up/Down user control -->
  <local:NumericUpDown />

</Window>

A figura a seguir mostra o NumericUpDown controle hospedado em um Window:

A custom UserControl

Para obter mais informações sobre controles personalizados, confira Visão geral da criação de controles.

Melhores práticas do WPF

Assim como com qualquer plataforma de desenvolvimento, o WPF pode ser usado de várias maneiras para atingir o resultado desejado. Como uma maneira de garantir que os aplicativos WPF forneçam a experiência de usuário necessária e atendam às demandas do público em geral, há melhores práticas para acessibilidade, globalização e localização e desempenho. Para saber mais, veja:

Próximas etapas

Analisamos os principais recursos do WPF. Agora, é hora de criar seu primeiro aplicativo do WPF.

Confira também