WPF - O controle TextBox e a tecla ENTER/TAB


Os controles WPF nem sempre possuem as mesmas propriedades e eventos que os controles das aplicações Windows Forms e neste artigo veremos como detectar e tratar o acionamento da Tecla ENTER em aplicações WPF no controle TextBox e como fazemos para tornar o comportamento do ENTER idêntico ao do acionamento da tecla TAB.

Nos exemplos mostrados neste artigo eu estou usando o Visual Studio 2010 beta 2 mas o comportamento será o mesmo para o VS 2008.

Para criar uma aplicação WPF abra o VS e no menu File selecione New Project e a seguir o template WPF Application informe (Wpf_ENTER) o nome e clique em OK.

A representação XAML para o controle TextBox é feita pelo elemento <TextBox />. Assim para criar um controle WPF usando XAML usamos a seguinte sintaxe:

Os atributos Width e Height definem a altura e a largura do TextBox. Abaixo temos um exemplo de criação de um controle TextBox com altura e largura definidos em um Canvas:

Para posicionar um controle TextBox você deve definir os atributos Top e Left do controle Container pai que no nosso caso é o container Canvas. Abaixo vemos um exemplo onde definimos Canvas.Top e Canvas.Left:

Para definir as cores de fundo do controle e a do frente usamos os atributos BackGround e ForeGround atribuindo a cor desejada:

Podemos também definir o atributo TextWrapping que permite que o fluxo de texto quebre e continue na linha seguinte. Os valores possíveis são : Wrap , NoWrap e WrapWithOverflow

Já os atributos VerticalScrollBarVisbility e HorizontalScrollBarVisibility que definem barras de rolagem vertical e horizontal. Os valores possíveis são: Auto, Disable, Hidden e Visible.

Podemos ainda usar os atributos MaxHeight, MaxWidth, MaxLines e MaxLength do controle TextBox para restringir a altura e largura máximas, o número máximo de linhas, e o comprimento máximo do TextBox. Da mesma forma os atributos MinHeight, MinWidht, MinLines, e MinLength restringem os valores mínimos.

Para não permitir a edição em um controle TextBox defina a propriedade IsReadOnly como true.

Agora veremos algo mais interessante; como tratar o acionamento da teclar ENTER.

O controle TextBox da WPF não possui o evento KeyPress do controle Windows Forms de mesmo nome, então como podemos saber quando o usuário pressionou a tecla ENTER quando o controle TextBox tiver o foco ?

Capturando a tecla ENTER

Podemos fazer isso de muitas maneiras e eu vou mostrar um exemplo onde vamos capturar o que foi informado em um controle TextBox após o acionamento da tecla ENTER;

Na janela Window1.xaml vamos definir uma interface usando os controles TextBox, TextBlock, e ListBox no interior de um StackPanel conforme o leiaute da figura abaixo:

O objetivo é capturar o que o usuário digitar no controle TextBox1 e exibir em um controle TextBlock e incluir também em um controle ListBox.

Para exibir o que o usuário digitou no controle TextBlock eu vou usar o evento KeyDown e definir um nome para a rotina que vamos chamar no code-behind.

Isso foi definido da seguinte forma: <TextBox Width="300" Height="30" Name="textBox1" KeyDown="OnKeyDownHandler"/>

No arquivo code-behind Window1.xaml.vb devemos definir a rotina OnKeyDownHandler da seguinte forma:

Class Window1

    Private Sub OnKeyDownHandler(ByVal sender As Object, ByVal e As KeyEventArgs)
        If (e.Key = Key.Return) Then
            textBlock1.Text = "Você informou : " + textBox1.Text
        End If
    End Sub

End Class

Neste código verificamos se a tecla pressionada é a tecla ENTER, e, neste caso exibimos o que foi digitado no TextBlock.

Para incluir o que foi digitado no controle ListBox vamos usar o evento PreviewKeyUp do controle TextBox definindo no arquivo code-behind o seguinte código:

  Private Sub TextBox1_PreviewKeyUp(ByVal sender As Object, ByVal e As System.Windows.Input.KeyEventArgs)_ 
 Handles textBox1.PreviewKeyUp
        If (e.Key = Key.Enter) Then
            ListBox1.Items.Add(textBox1.Text)
            textBox1.Text = ""
            e.Handled = True
        End If
    End Sub

O código acima verifica se a tecla ENTER foi pressionada e inclui o conteúdo do TextBox no controle ListBox.Executando o projeto iremos obter o seguinte resultado:


Fazendo a tecla ENTER se comportar como TAB
(Mudar o foco para outro controle)


A tecla TAB é usada para mudar o foco para outro controle. O problema é que os usuários costumam pressionar a tecla ENTER para mudar o foco.

Para resolver este problema podemos mudar o comportamento da tecla ENTER de forma que quando ela for pressionada o foco seja movido para outro controle.

Para fazer isso vamos usar a classe TraversalRequest.

A classe TraversalRequest representa uma requisição para mover o foco para outro controle.

Essa classe é usada como um parâmetro de entrada para o método UIElement.MoveFocus.

Você irá definir propriedades na classe TraversalRequest com o objetivo de personalizar o comportamento do foco quando você solicitar que o foco seja movido para outro elemento.

Vamos incluir uma nova janela Window2.xaml no projeto e incluir nesta janela 3 controles TextBox conforme a figura abaixo:

A seguir devemos definir o arquivo code-behind Window2.xaml.vb o seguinte código:

Partial Public Class Window2

    Private Sub Window1_PreviewKeyDown(ByVal sender As System.Object, ByVal e As System.Windows.Input.KeyEventArgs) _
 Handles MyBase.PreviewKeyDown

        Dim elemento = TryCast(e.OriginalSource, UIElement)

        If elemento Is Nothing Then
            Return
        End If

        If e.Key = Key.Enter Or e.Key = Key.Down Then
            elemento.MoveFocus(New TraversalRequest(FocusNavigationDirection.[Next]))
        End If

        If e.Key = Key.Up Then
            elemento.MoveFocus(New TraversalRequest(FocusNavigationDirection.Up))
        End If

    End Sub
End Class


No código acima estamos usando o evento PreviewKeyDown da janela Window1 e criando uma variável a partir do controle atual que é indicado por
e.OriginalSource, pois será a partir dele que vamos mudar o foco;

Em seguida verificamos se a variável controle é nula , e, neste caso nada será feito.(Return)

Se a variável não for nula passamos então a verificar se a tecla ENTER foi acionada, e, em caso positivo chamamos o método MoveFocus() para mover o foco para outro controle.(TraversalRequest(FocusNavigationDirection.[Next]))

Aqui é que entra a classe TraversalRequest. Passamos uma nova instância dessa classe para o método MoveFocus() indicando a direção através da enumeração FocusNavigationDirection que pode receber os seguintes valores: Next, Previous, First, Last, Left, Right, Up e Down.

A movimentação do foco é feita de acordo com o TabOrder do formulário ou pela posição dos controles no mesmo.

Observe que no código acima tratamos a tecla ENTER e a tecla Down (Seta para baixo) para mover o foco para outro controle e a tecla UP (seta para cima) para retornar ao controle anterior.

Executando o projeto iremos obter:

Estando o foco inicialmente no controle TextBox (1) digitamos Macoratti e...

Pressionando a tecla ENTER ou a tecla Seta para baixo o foco será movido para os
controles TextBox 2 e 3 respectivamente;

Se pressionarmos a tecla seta para cima retornaremos aos controles TextBox 2 e 1.

Uma outra forma de obter o mesmo resultado para a tecla ENTER mover o foco é definir o código abaixo no evento PreviewKeyDown da janela Window1:

Nota: Lembre-se que em uma aplicação WPF, os eventos são propagados por toda a árvore de elementos, e dessa forma , os eventos de tecla obrigatoriamente passam pela janela, independente de onde tenham sido gerados.

  Private Sub Window1_PreviewKeyDown(ByVal sender As System.Object, ByVal e As System.Windows.Input.KeyEventArgs) _ 
Handles MyBase.PreviewKeyDown

    If e.Key = Key.[Return] Then
            Dim direcaoFoco As FocusNavigationDirection = FocusNavigationDirection.[Next]
            Dim requisicao As New TraversalRequest(direcaoFoco)
            Dim elementoComFoco As UIElement = TryCast(Keyboard.FocusedElement, UIElement)
            If elementoComFoco IsNot Nothing Then
                elementoComFoco.MoveFocus(requisicao)
            End If
            e.Handled = True
        End If

    End Sub

E era isso que eu tinha para escrever. Aguarde mais dicas sobre WPF.

Pegue o projeto completo aqui: Wpf_ENTER.zip

Eu sei é apenas WPF, mas eu gosto...

Referências:


José Carlos Macoratti