Desenvolvimento

22 abr, 2010

WPF – O controle TextBox e a tecla enter/tab

Publicidade

Os controles WPF nem sempre possuem
as mesmas propriedades e eventos que os controles das
aplicações Windows Forms. Veremos aqui 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, 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:

  • <TextBox />
  • <TextBox></TextBox>

  • <TextBox>Macoratti</TextBox>

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 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
a 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
tecla 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. 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 esse 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, nessa janela, três controles TextBox, conforme a
figura abaixo:

A
seguir, devemos definir, no 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. 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 de 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, independentemente 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…