Compartilhar via


O que são controles?

O WPF (Windows Presentation Foundation) é fornecido com muitos dos componentes comuns da interface do usuário que são usados em quase todos os aplicativos do Windows, como Button, Label, TextBoxe MenuListBox. Historicamente, esses objetos são chamados de controles. O termo "controle" é usado livremente para significar qualquer classe que represente um objeto visível em um aplicativo. É importante observar que uma classe não precisa herdar da Control classe para ter uma presença visível. As classes que herdam da Control classe contêm um ControlTemplate, que permite que o consumidor de um controle altere radicalmente a aparência do controle sem precisar criar uma nova subclasse. Este artigo discute como os controles (tanto aqueles que herdam da Control classe quanto aqueles que não herdam) são comumente usados no WPF.

Criar uma instância de um controle

Você pode adicionar um controle a um aplicativo usando XAML (Extensible Application Markup Language) ou código. Por exemplo, considere a imagem a seguir de uma janela do WPF que solicita ao usuário seu nome e endereço:

Uma captura de tela de um aplicativo WPF com duas caixas de texto rotuladas como nome e endereço. Dois botões estão visíveis. Um botão se chama

Essa janela tem seis controles: dois rótulos, duas caixas de texto e dois botões. O XAML é usado para criar esses controles, conforme demonstrado no seguinte snippet:

<Window x:Class="Examples.ExampleApp"
        xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
        xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
        Title="Input Record" Height="Auto" Width="300" SizeToContent="Height">
    <Grid Margin="5">
        <Grid.RowDefinitions>
            <RowDefinition Height="30"/>
            <RowDefinition Height="30"/>
            <RowDefinition Height="30"/>
        </Grid.RowDefinitions>
        <Grid.ColumnDefinitions>
            <ColumnDefinition/>
            <ColumnDefinition/>
        </Grid.ColumnDefinitions>

        <Label>Enter your name:</Label>
        <TextBox Grid.Row="0" Grid.Column="1" Name="FirstName" Margin="2" />

        <Label Grid.Row="1">Enter your address:</Label>
        <TextBox Grid.Row="1" Grid.Column="1" Name="LastName" Margin="2" />

        <Button Grid.Row="2" Grid.Column="0" Name="Reset" Margin="2">Reset</Button>
        <Button Grid.Row="2" Grid.Column="1" Name="Submit" Margin="2">Submit</Button>
    </Grid>
</Window>

Todos os controles podem ser criados da mesma forma no XAML. A mesma janela pode ser criada no código:

// Grid container which is the content of the Window
Grid container = new() { Margin = new Thickness(5) };
container.RowDefinitions.Add(new RowDefinition());
container.RowDefinitions.Add(new RowDefinition());
container.RowDefinitions.Add(new RowDefinition());
container.ColumnDefinitions.Add(new ColumnDefinition());
container.ColumnDefinitions.Add(new ColumnDefinition());

// Create the two labels, assign the second label to the second row
Label labelName = new() { Content = "Enter your name:" };
container.Children.Add(labelName);

Label labelAddress = new() { Content = "Enter your address:" };
Grid.SetRow(labelAddress, 1);
container.Children.Add(labelAddress);

// Create the two textboxes, assign both to the second column and
// assign the second textbox to the second row.
TextBox textboxName = new() { Margin = new Thickness(2) };
Grid.SetColumn(textboxName, 1);
container.Children.Add(textboxName);

TextBox textboxAddress = new() { Margin = new Thickness(2) };
Grid.SetRow(textboxAddress, 1);
Grid.SetColumn(textboxAddress, 1);
container.Children.Add(textboxAddress);

// Create the two buttons, assign both to the third row and
// assign the second button to the second column.
Button buttonReset = new() { Margin = new Thickness(2), Content = "Reset" };
Grid.SetRow(buttonReset, 2);
container.Children.Add(buttonReset);

Button buttonSubmit = new() { Margin = new Thickness(2), Content = "Submit" };
Grid.SetColumn(buttonSubmit, 1);
Grid.SetRow(buttonSubmit, 2);
container.Children.Add(buttonSubmit);

// Create the popup window and assign the container (Grid) as its content
Window inputWindow = new()
{
    Title = "Input Record",
    Height = double.NaN,
    Width = 300,
    SizeToContent = SizeToContent.Height,
    Content = container
};

inputWindow.Show();
' Grid container which is the content of the Window
Dim container As New Grid() With {.Margin = New Thickness(5)}
container.RowDefinitions.Add(New RowDefinition())
container.RowDefinitions.Add(New RowDefinition())
container.RowDefinitions.Add(New RowDefinition())
container.ColumnDefinitions.Add(New ColumnDefinition())
container.ColumnDefinitions.Add(New ColumnDefinition())

' Create the two labels, assign the second label to the second row
Dim labelName As New Label() With {.Content = "Enter your name:"}
container.Children.Add(labelName)

Dim labelAddress As New Label() With {.Content = "Enter your address:"}
Grid.SetRow(labelAddress, 1)
container.Children.Add(labelAddress)

' Create the two textboxes, assign both to the second column and
' assign the second textbox to the second row.
Dim textboxName As New TextBox() With {.Margin = New Thickness(2)}
Grid.SetColumn(textboxName, 1)
container.Children.Add(textboxName)

Dim textboxAddress As New TextBox() With {.Margin = New Thickness(2)}
Grid.SetRow(textboxAddress, 1)
Grid.SetColumn(textboxAddress, 1)
container.Children.Add(textboxAddress)

' Create the two buttons, assign both to the third row and
' assign the second button to the second column.
Dim buttonReset As New Button() With {.Margin = New Thickness(2), .Content = "Reset"}
Grid.SetRow(buttonReset, 2)
container.Children.Add(buttonReset)

Dim buttonSubmit As New Button() With {.Margin = New Thickness(2), .Content = "Submit"}
Grid.SetColumn(buttonSubmit, 1)
Grid.SetRow(buttonSubmit, 2)
container.Children.Add(buttonSubmit)

' Create the window and assign the container (Grid) as its content
Dim inputWindow As New Window() With
{
    .Title = "Input Record",
    .Height = Double.NaN,
    .Width = 300,
    .SizeToContent = SizeToContent.Height,
    .Content = container
}

inputWindow.Show()

Assinar eventos

Você pode assinar um evento de controle usando XAML ou código, mas só pode manipulá-lo por meio de código.

No XAML, o evento é definido como um atributo no elemento. Você não pode usar a <Element.Event>handler<Element.Event> notação para eventos. O trecho de código a seguir demonstra como assinar o evento Click de um Button:

<Button Click="Submit_Click" Grid.Row="2" Grid.Column="1" Name="Submit" Margin="2">Submit</Button>

E veja como fazer o mesmo no código:

Button buttonSubmit = new() { Margin = new Thickness(2), Content = "Submit" };
buttonSubmit.Click += Submit_Click;
Dim buttonSubmit As New Button() With {.Margin = New Thickness(2), .Content = "Submit"}
AddHandler buttonSubmit.Click, AddressOf Submit_Click

O trecho de código a seguir manipula o Click evento de um Button.

private void Submit_Click(object sender, RoutedEventArgs e)
{
    MessageBox.Show("Someone clicked the submit button.");
}
Private Sub Submit_Click(sender As Object, e As Windows.RoutedEventArgs)
    MessageBox.Show("Someone clicked the submit button.")
End Sub

Alterar a aparência de um controle

É comum alterar a aparência de um controle para ajustar a aparência do seu aplicativo. Você pode alterar a aparência de um controle fazendo um dos seguintes procedimentos, dependendo do que você deseja realizar:

  • Altere o valor de uma propriedade do controle.
  • Crie um Style para o controle.
  • Crie um novo ControlTemplate para o controle.

Alterar a propriedade de um controle

Muitos controles têm propriedades que permitem alterar a forma como o controle aparece, como a tela de fundo de um botão. Você pode definir as propriedades de valor em XAML e código. O exemplo a seguir define as propriedades Background, FontSize e FontWeight em um componente Button no XAML:

<Button Grid.Row="2" Grid.Column="1" Name="Submit" Margin="2" Content="Submit">
    <Button.FontSize>18</Button.FontSize>
    <Button.FontWeight>Bold</Button.FontWeight>
    <Button.Background>
        <LinearGradientBrush>
            <GradientStop Color="#0073E6" Offset="0.0" />
            <GradientStop Color="#81D4FA" Offset="0.9" />
        </LinearGradientBrush>
    </Button.Background>
</Button>

E veja como fazer o mesmo no código:

Button buttonSubmit = new() { Margin = new Thickness(2), Content = "Submit" };
buttonSubmit.FontSize = 18f;
buttonSubmit.FontWeight = FontWeights.Bold;
buttonSubmit.Background =
    new LinearGradientBrush(
        (Color)ColorConverter.ConvertFromString("#0073E6"),
        (Color)ColorConverter.ConvertFromString("#81D4FA"),
        new Point(0d, 0d),
        new Point(0.9d, 0d));
Dim buttonSubmit As New Button() With {.Margin = New Thickness(2), .Content = "Submit"}
buttonSubmit.FontSize = 18.0F
buttonSubmit.FontWeight = FontWeights.Bold
buttonSubmit.Background =
        New LinearGradientBrush(
            ColorConverter.ConvertFromString("#0073E6"),
            ColorConverter.ConvertFromString("#81D4FA"),
            New Point(0D, 0D),
            New Point(0.9D, 0D))

A janela de exemplo agora se parece com a seguinte imagem:

Uma captura de tela de um aplicativo WPF com duas caixas de texto rotuladas como nome e endereço. Dois botões estão visíveis. Um botão se chama

Criar um estilo para um controle

O WPF oferece uma ampla capacidade de especificar a aparência dos controles criando um Style, em vez de definir propriedades em cada controle. Style definições de propriedades são normalmente especificadas em XAML em um ResourceDictionary, como na propriedade Resources de um controle ou janela. Os recursos são aplicados ao escopo no qual são declarados. Para obter mais informações, consulte Visão geral dos recursos XAML.

O exemplo a seguir aplica um Style a todos os Button contidos no mesmo Grid que define o estilo.

<Grid.Resources>
    <Style TargetType="{x:Type Button}">
        <Style.Setters>
            <Setter Property="FontSize" Value="18" />
            <Setter Property="FontWeight" Value="Bold" />
            <Setter Property="Background">
                <Setter.Value>
                    <LinearGradientBrush>
                        <GradientStop Color="#0073E6" Offset="0.0" />
                        <GradientStop Color="#81D4FA" Offset="0.9" />
                    </LinearGradientBrush>
                </Setter.Value>
            </Setter>
        </Style.Setters>
    </Style>
</Grid.Resources>

E veja como fazer o mesmo no código:

Grid container = new() { Margin = new Thickness(5) };
container.RowDefinitions.Add(new RowDefinition());
container.RowDefinitions.Add(new RowDefinition());
container.RowDefinitions.Add(new RowDefinition());
container.ColumnDefinitions.Add(new ColumnDefinition());
container.ColumnDefinitions.Add(new ColumnDefinition());

Style buttonStyle = new(typeof(Button));
buttonStyle.Setters.Add(new Setter(Button.FontSizeProperty, 18d));
buttonStyle.Setters.Add(new Setter(Button.FontWeightProperty, FontWeights.Bold));
buttonStyle.Setters.Add(new Setter(Button.BackgroundProperty,
    new LinearGradientBrush(
        (Color)ColorConverter.ConvertFromString("#0073E6"),
        (Color)ColorConverter.ConvertFromString("#81D4FA"),
        new Point(0d, 0d),
        new Point(0.9d, 0d))));

container.Resources.Add(typeof(Button), buttonStyle);
Dim container As New Grid() With {.Margin = New Thickness(5)}
container.RowDefinitions.Add(New RowDefinition())
container.RowDefinitions.Add(New RowDefinition())
container.RowDefinitions.Add(New RowDefinition())
container.ColumnDefinitions.Add(New ColumnDefinition())
container.ColumnDefinitions.Add(New ColumnDefinition())

Dim buttonStyle As New Style(GetType(Button))
buttonStyle.Setters.Add(New Setter(Button.FontSizeProperty, 18.0R))
buttonStyle.Setters.Add(New Setter(Button.FontWeightProperty, FontWeights.Bold))
buttonStyle.Setters.Add(New Setter(Button.BackgroundProperty,
        New LinearGradientBrush(
            ColorConverter.ConvertFromString("#0073E6"),
            ColorConverter.ConvertFromString("#81D4FA"),
            New Point(0D, 0D),
            New Point(0.9D, 0D))))

container.Resources.Add(GetType(Button), buttonStyle)

A imagem a seguir mostra o estilo aplicado à grade da janela, que altera a aparência dos dois botões:

Uma captura de tela de um aplicativo WPF com duas caixas de texto rotuladas como nome e endereço. Dois botões estão visíveis. Um botão se chama

Em vez de aplicar o estilo a todos os controles de um tipo específico, eles também podem ser atribuídos a controles específicos adicionando uma chave ao estilo no dicionário de recursos e fazendo referência a Style essa chave na propriedade do controle. Para obter mais informações sobre estilos, consulte Estilo e Modelagem.

Criar um ControlTemplate

Um Style permite que você defina propriedades em vários controles de cada vez, mas às vezes você pode querer personalizar a aparência de um controle além do que você pode fazer com um Style. Classes que herdam da Control classe têm um ControlTemplate, que define a estrutura e a aparência de um controle.

Considere o Button controle, um controle comum usado por quase todos os aplicativos. O comportamento principal de um botão é permitir que um aplicativo execute alguma ação quando o usuário selecionar o botão. Por padrão, o botão em WPF aparece como um retângulo elevado. Ao desenvolver um aplicativo, talvez você queira aproveitar o comportamento de um botão, ou seja, como o usuário interage com o botão, o que gera um Click evento, mas você pode alterar a aparência do botão além do que pode fazer alterando as propriedades do botão. Nesse caso, você pode criar um novo ControlTemplate.

O exemplo a seguir cria um ControlTemplate para um Button. O ControlTemplate cria um visual para o Button que apresenta uma borda com cantos arredondados e uma tela de fundo de gradiente.

<Button Grid.Row="2" Grid.Column="1" Name="Submit" Margin="2" Content="Submit">
    <Button.Template>
        <ControlTemplate TargetType="Button">
            <Border Name="Border" CornerRadius="10" BorderThickness="1" BorderBrush="Black">
                <Border.Background>
                    <LinearGradientBrush StartPoint="0,0.5" 
                         EndPoint="1,0.5">
                        <GradientStop Color="{Binding Background.Color, RelativeSource={RelativeSource TemplatedParent}}" Offset="0.0" />
                        <GradientStop Color="PeachPuff" Offset="0.9" />
                    </LinearGradientBrush>
                </Border.Background>
                <ContentPresenter Margin="2" HorizontalAlignment="Center" VerticalAlignment="Center" RecognizesAccessKey="True"/>
            </Border>
            <ControlTemplate.Triggers>
                <!--Change the appearance of the button when the user clicks it.-->
                <Trigger Property="IsPressed" Value="true">
                    <Setter TargetName="Border" Property="Background">
                        <Setter.Value>
                            <LinearGradientBrush StartPoint="0,0.5" EndPoint="1,0.5">
                                <GradientStop Color="{Binding Background.Color, RelativeSource={RelativeSource TemplatedParent}}" Offset="0.0" />
                                <GradientStop Color="LightBlue" Offset="0.9" />
                            </LinearGradientBrush>
                        </Setter.Value>
                    </Setter>
                </Trigger>
            </ControlTemplate.Triggers>
        </ControlTemplate>
    </Button.Template>
</Button>

Observação

A Background propriedade do Button deve ser definida como um SolidColorBrush para que o exemplo funcione corretamente.

E veja como fazer o mesmo no código. O código a seguir cria uma cadeia de caracteres XAML e a analisa para gerar um modelo que pode ser aplicado, que é a maneira compatível de gerar um modelo em tempo de execução.

Button buttonSubmit = new() { Margin = new Thickness(2), Content = "Submit" };

// Create the XAML used to define the button template
const string xaml = """
    <ControlTemplate TargetType="Button">
        <Border Name="Border" CornerRadius="10" BorderThickness="1" BorderBrush="Black">
            <Border.Background>
                <LinearGradientBrush StartPoint="0,0.5" 
                     EndPoint="1,0.5">
                    <GradientStop Color="{Binding Background.Color, RelativeSource={RelativeSource TemplatedParent}}" Offset="0.0" />
                    <GradientStop Color="PeachPuff" Offset="0.9" />
                </LinearGradientBrush>
            </Border.Background>
            <ContentPresenter Margin="2" HorizontalAlignment="Center" VerticalAlignment="Center" RecognizesAccessKey="True"/>
        </Border>
        <ControlTemplate.Triggers>
            <!--Change the appearance of the button when the user clicks it.-->
            <Trigger Property="IsPressed" Value="true">
                <Setter TargetName="Border" Property="Background">
                    <Setter.Value>
                        <LinearGradientBrush StartPoint="0,0.5" EndPoint="1,0.5">
                            <GradientStop Color="{Binding Background.Color, RelativeSource={RelativeSource TemplatedParent}}" Offset="0.0" />
                            <GradientStop Color="LightBlue" Offset="0.9" />
                        </LinearGradientBrush>
                    </Setter.Value>
                </Setter>
            </Trigger>
        </ControlTemplate.Triggers>
    </ControlTemplate>
    """;

// Load the XAML into a stream that can be parsed
using MemoryStream stream = new(System.Text.Encoding.UTF8.GetBytes(xaml));

// Create a parser context and add the default namespace and 
// the x namespace, which is common to WPF XAML
System.Windows.Markup.ParserContext context = new();
context.XmlnsDictionary.Add("", "http://schemas.microsoft.com/winfx/2006/xaml/presentation");
context.XmlnsDictionary.Add("x", "http://schemas.microsoft.com/winfx/2006/xaml");

// Parse the XAML and assign it to the button's template
buttonSubmit.Template = (ControlTemplate)System.Windows.Markup.XamlReader.Load(stream, context);

// Set the other properties of the button
Grid.SetColumn(buttonSubmit, 1);
Grid.SetRow(buttonSubmit, 2);

// Assign the button to the grid container
container.Children.Add(buttonSubmit);
Dim buttonSubmit As New Button() With {.Margin = New Thickness(2), .Content = "Submit"}

' Create the XAML used to define the button template
Const xaml As String = "
    <ControlTemplate TargetType=""Button"">
        <Border Name=""Border"" CornerRadius=""10"" BorderThickness=""1"" BorderBrush=""Black"">
            <Border.Background>
                <LinearGradientBrush StartPoint=""0,0.5"" 
                     EndPoint=""1,0.5"">
                    <GradientStop Color=""{Binding Background.Color, RelativeSource={RelativeSource TemplatedParent}}"" Offset=""0.0"" />
                    <GradientStop Color=""PeachPuff"" Offset=""0.9"" />
                </LinearGradientBrush>
            </Border.Background>
            <ContentPresenter Margin=""2"" HorizontalAlignment=""Center"" VerticalAlignment=""Center"" RecognizesAccessKey=""True""/>
        </Border>
        <ControlTemplate.Triggers>
            <!--Change the appearance of the button when the user clicks it.-->
            <Trigger Property=""IsPressed"" Value=""true"">
                <Setter TargetName=""Border"" Property=""Background"">
                    <Setter.Value>
                        <LinearGradientBrush StartPoint=""0,0.5"" EndPoint=""1,0.5"">
                            <GradientStop Color=""{Binding Background.Color, RelativeSource={RelativeSource TemplatedParent}}"" Offset=""0.0"" />
                            <GradientStop Color=""LightBlue"" Offset=""0.9"" />
                        </LinearGradientBrush>
                    </Setter.Value>
                </Setter>
            </Trigger>
        </ControlTemplate.Triggers>
    </ControlTemplate>"

' Load the XAML into a stream that can be parsed
Using stream As New MemoryStream(System.Text.Encoding.UTF8.GetBytes(xaml))

    ' Create a parser context and add the default namespace and 
    ' the x namespace, which is common to WPF XAML
    Dim context = New System.Windows.Markup.ParserContext()
    context.XmlnsDictionary.Add("", "http://schemas.microsoft.com/winfx/2006/xaml/presentation")
    context.XmlnsDictionary.Add("x", "http://schemas.microsoft.com/winfx/2006/xaml")

    ' Parse the XAML and assign it to the button's template
    buttonSubmit.Template = System.Windows.Markup.XamlReader.Load(stream, context)
End Using

' Set the other properties of the button
Grid.SetColumn(buttonSubmit, 1)
Grid.SetRow(buttonSubmit, 2)

' Assign the button to the grid container
container.Children.Add(buttonSubmit)

A imagem a seguir mostra a aparência do modelo quando aplicado:

Uma captura de tela de um aplicativo WPF com duas caixas de texto rotuladas como nome e endereço. Dois botões estão visíveis. Um botão se chama

No exemplo anterior, ControlTemplate é aplicado a um único botão. No entanto, um ControlTemplate pode ser atribuído a um Style e aplicado a todos os botões, como o que foi demonstrado na seção Criar um estilo para um controle .

Para obter mais informações sobre como aproveitar os recursos exclusivos que um modelo fornece, consulte Estilo e Modelagem.

Conteúdo rico em controles

A maioria das classes que herdam da Control classe tem a capacidade de conter conteúdo avançado. Por exemplo, um Label pode conter qualquer objeto, como uma cadeia de caracteres, um Imageou um Panel. As classes a seguir oferecem suporte para conteúdo avançado e atuam como classes base para a maioria dos controles no WPF: