Visão geral da entrada
O subsistema Windows Presentation Foundation (WPF) fornece uma API poderosa para obter entrada de uma variedade de dispositivos, incluindo mouse, teclado, toque e caneta. Este tópico descreve os serviços fornecidos pelo WPF e explica a arquitetura dos sistemas de entrada.
API de entrada
A exposição da API de entrada primária é encontrada nas classes de elemento base: UIElement, ContentElement, FrameworkElemente FrameworkContentElement. Para obter mais informações sobre os elementos base, consulte Visão geral dos elementos básicos. Essas classes fornecem funcionalidade para eventos de entrada relacionados a pressionamentos de teclas, botões do mouse, roda do mouse, movimento do mouse, gerenciamento de foco e captura do mouse, para citar alguns. Ao colocar a API de entrada nos elementos base, em vez de tratar todos os eventos de entrada como um serviço, a arquitetura de entrada permite que os eventos de entrada sejam originados por um objeto específico na interface do usuário e ofereça suporte a um esquema de roteamento de eventos em que mais de um elemento tem a oportunidade de manipular um evento de entrada. Muitos eventos de entrada têm um par de eventos associados a eles. Por exemplo, o evento key down está associado aos eventos KeyDown e PreviewKeyDown. A diferença nesses eventos está em como eles são roteados para o elemento de destino. Eventos de pré-visualização percorrem a árvore de elementos, desde o elemento raiz até o elemento de destino. Os eventos de propagação propagam-se do elemento de destino para o elemento raiz. O roteamento de eventos no WPF é discutido com mais detalhes posteriormente nesta visão geral e no Visão geral de eventos roteados.
Classes de teclado e mouse
Além da API de entrada nas classes de elemento base, a classe Keyboard e as classes Mouse fornecem API adicional para trabalhar com entrada de teclado e mouse.
Exemplos de API de entrada na classe Keyboard são a propriedade Modifiers, que retorna o ModifierKeys pressionado no momento, e o método IsKeyDown, que determina se uma tecla especificada é pressionada.
O exemplo a seguir usa o método GetKeyStates para determinar se um Key está no estado de inatividade.
// Uses the Keyboard.GetKeyStates to determine if a key is down.
// A bitwise AND operation is used in the comparison.
// e is an instance of KeyEventArgs.
if ((Keyboard.GetKeyStates(Key.Return) & KeyStates.Down) > 0)
{
btnNone.Background = Brushes.Red;
}
' Uses the Keyboard.GetKeyStates to determine if a key is down.
' A bitwise AND operation is used in the comparison.
' e is an instance of KeyEventArgs.
If (Keyboard.GetKeyStates(Key.Return) And KeyStates.Down) > 0 Then
btnNone.Background = Brushes.Red
Exemplos de API de entrada na classe Mouse são MiddleButton, que obtém o estado do botão do meio do mouse, e DirectlyOver, que obtém o elemento sobre o qual o ponteiro do mouse está no momento.
O exemplo a seguir determina se o LeftButton no mouse está no estado Pressed.
if (Mouse.LeftButton == MouseButtonState.Pressed)
{
UpdateSampleResults("Left Button Pressed");
}
If Mouse.LeftButton = MouseButtonState.Pressed Then
UpdateSampleResults("Left Button Pressed")
End If
As classes Mouse e Keyboard são abordadas com mais detalhes ao longo desta visão geral.
Entrada Stylus
WPF integrou o suporte para o Stylus. O Stylus é um dispositivo de entrada de caneta popularizado pelo Tablet PC. Os aplicativos WPF podem tratar a caneta como um mouse usando a API do mouse, mas o WPF também expõe uma abstração de dispositivo stylus que usa um modelo semelhante ao teclado e mouse. Todas as APIs relacionadas ao stylus contêm a palavra "Stylus".
Como a caneta pode atuar como um mouse, os aplicativos que suportam apenas a entrada do mouse ainda podem obter algum nível de suporte à caneta automaticamente. Quando a caneta é usada dessa maneira, o aplicativo tem a oportunidade de manipular o evento de caneta apropriado e, em seguida, lida com o evento de mouse correspondente. Além disso, serviços de nível superior, como entrada de tinta, também estão disponíveis através da abstração do dispositivo stylus. Para obter mais informações sobre tinta como entrada, consulte Introdução à tinta.
Roteamento de eventos
Um FrameworkElement pode conter outros elementos como elementos-filho no seu modelo de conteúdo, formando uma árvore de elementos. No WPF, o elemento pai pode participar da entrada direcionada a seus elementos filhos ou outros descendentes entregando eventos. Isso é especialmente útil para criar controles a partir de controles menores, um processo conhecido como "composição de controle" ou "composição". Para obter mais informações sobre árvores de elementos e como as árvores de elementos se relacionam com rotas de eventos, consulte Árvores no WPF.
O roteamento de eventos é o processo de encaminhamento de eventos para vários elementos, de modo que um determinado objeto ou elemento ao longo da rota possa optar por oferecer uma resposta significativa (por meio de manipulação) a um evento que pode ter sido originado por um elemento diferente. Os eventos roteados usam um dos três mecanismos de roteamento: direto, borbulhante e tunelamento. No roteamento direto, o elemento source é o único elemento notificado e o evento não é roteado para nenhum outro elemento. No entanto, o evento roteado direto ainda oferece alguns recursos adicionais que estão presentes apenas para eventos roteados, em oposição aos eventos CLR padrão. O borbulhar funciona na árvore de elementos notificando primeiro o elemento que originou o evento, depois o elemento pai e assim por diante. O tunelamento começa na raiz da árvore de elementos e trabalha para baixo, terminando com o elemento de origem original. Para obter mais informações sobre eventos roteados, consulte Visão Geral de Eventos Roteados.
Os eventos de entrada do WPF geralmente vêm em pares que consistem em um evento de tunelamento e um evento borbulhante. Os eventos de tunelamento são distinguidos dos eventos borbulhantes com o prefixo "Preview". Por exemplo, PreviewMouseMove é a versão de tunelamento de um evento de movimento do mouse e MouseMove é a versão borbulhante desse evento. Esse emparelhamento de eventos é uma convenção que é implementada no nível do elemento e não é um recurso inerente do sistema de eventos WPF. Para obter detalhes, consulte a seção Eventos de entrada do WPF em Routed Events Overview .
Manipulando eventos de entrada
Para receber entrada em um elemento, um manipulador de eventos deve ser associado a esse evento específico. Em XAML, isso é simples: você faz referência ao nome do evento como um atributo do elemento que estará escutando esse evento. Em seguida, defina o valor do atributo para o nome do manipulador de eventos que você definir, com base em um delegado. O manipulador de eventos deve ser escrito em código como C# e pode ser incluído em um arquivo code-behind.
Os eventos do teclado ocorrem quando o sistema operacional relata ações-chave que ocorrem enquanto o foco do teclado está em um elemento. Os eventos de mouse e caneta se enquadram em duas categorias: eventos que relatam alterações na posição do ponteiro em relação ao elemento e eventos que relatam alterações no estado dos botões do dispositivo.
Exemplo de evento de entrada de teclado
O exemplo a seguir detecta uma tecla de seta para a esquerda. É criado um StackPanel que tem um Button. Um manipulador de eventos para ouvir o pressionar da tecla de seta para a esquerda está anexado na instância Button.
A primeira seção do exemplo cria o StackPanel e o Button e anexa o manipulador de eventos para o KeyDown.
<StackPanel>
<Button Background="AliceBlue"
KeyDown="OnButtonKeyDown"
Content="Button1"/>
</StackPanel>
// Create the UI elements.
StackPanel keyboardStackPanel = new StackPanel();
Button keyboardButton1 = new Button();
// Set properties on Buttons.
keyboardButton1.Background = Brushes.AliceBlue;
keyboardButton1.Content = "Button 1";
// Attach Buttons to StackPanel.
keyboardStackPanel.Children.Add(keyboardButton1);
// Attach event handler.
keyboardButton1.KeyDown += new KeyEventHandler(OnButtonKeyDown);
' Create the UI elements.
Dim keyboardStackPanel As New StackPanel()
Dim keyboardButton1 As New Button()
' Set properties on Buttons.
keyboardButton1.Background = Brushes.AliceBlue
keyboardButton1.Content = "Button 1"
' Attach Buttons to StackPanel.
keyboardStackPanel.Children.Add(keyboardButton1)
' Attach event handler.
AddHandler keyboardButton1.KeyDown, AddressOf OnButtonKeyDown
A segunda seção é escrita em código e define o manipulador de eventos. Quando a seta esquerda é pressionada e o Button tem o foco do teclado, o manipulador é executado e a cor Background do Button é alterada. Se a tecla for pressionada, mas não for a tecla de seta para a esquerda, a cor Background do Button será alterada de volta à sua cor inicial.
private void OnButtonKeyDown(object sender, KeyEventArgs e)
{
Button source = e.Source as Button;
if (source != null)
{
if (e.Key == Key.Left)
{
source.Background = Brushes.LemonChiffon;
}
else
{
source.Background = Brushes.AliceBlue;
}
}
}
Private Sub OnButtonKeyDown(ByVal sender As Object, ByVal e As KeyEventArgs)
Dim source As Button = TryCast(e.Source, Button)
If source IsNot Nothing Then
If e.Key = Key.Left Then
source.Background = Brushes.LemonChiffon
Else
source.Background = Brushes.AliceBlue
End If
End If
End Sub
Exemplo de evento de entrada do mouse
No exemplo a seguir, a cor Background de um Button é alterada quando o ponteiro do mouse entra na Button. A cor Background é restaurada quando o rato sai do Button.
A primeira seção do exemplo cria o StackPanel e o controle Button e anexa os manipuladores de eventos para os eventos MouseEnter e MouseLeave ao Button.
<StackPanel>
<Button Background="AliceBlue"
MouseEnter="OnMouseExampleMouseEnter"
MouseLeave="OnMosueExampleMouseLeave">Button
</Button>
</StackPanel>
// Create the UI elements.
StackPanel mouseMoveStackPanel = new StackPanel();
Button mouseMoveButton = new Button();
// Set properties on Button.
mouseMoveButton.Background = Brushes.AliceBlue;
mouseMoveButton.Content = "Button";
// Attach Buttons to StackPanel.
mouseMoveStackPanel.Children.Add(mouseMoveButton);
// Attach event handler.
mouseMoveButton.MouseEnter += new MouseEventHandler(OnMouseExampleMouseEnter);
mouseMoveButton.MouseLeave += new MouseEventHandler(OnMosueExampleMouseLeave);
' Create the UI elements.
Dim mouseMoveStackPanel As New StackPanel()
Dim mouseMoveButton As New Button()
' Set properties on Button.
mouseMoveButton.Background = Brushes.AliceBlue
mouseMoveButton.Content = "Button"
' Attach Buttons to StackPanel.
mouseMoveStackPanel.Children.Add(mouseMoveButton)
' Attach event handler.
AddHandler mouseMoveButton.MouseEnter, AddressOf OnMouseExampleMouseEnter
AddHandler mouseMoveButton.MouseLeave, AddressOf OnMosueExampleMouseLeave
A segunda seção do exemplo é escrita em código e define os manipuladores de eventos. Quando o mouse entra no Button, a cor Background do Button é alterada para SlateGray. Quando o mouse sai do Button, a cor Background do Button é alterada de volta para AliceBlue.
private void OnMouseExampleMouseEnter(object sender, MouseEventArgs e)
{
// Cast the source of the event to a Button.
Button source = e.Source as Button;
// If source is a Button.
if (source != null)
{
source.Background = Brushes.SlateGray;
}
}
Private Sub OnMouseExampleMouseEnter(ByVal sender As Object, ByVal e As MouseEventArgs)
' Cast the source of the event to a Button.
Dim source As Button = TryCast(e.Source, Button)
' If source is a Button.
If source IsNot Nothing Then
source.Background = Brushes.SlateGray
End If
End Sub
private void OnMosueExampleMouseLeave(object sender, MouseEventArgs e)
{
// Cast the source of the event to a Button.
Button source = e.Source as Button;
// If source is a Button.
if (source != null)
{
source.Background = Brushes.AliceBlue;
}
}
Private Sub OnMosueExampleMouseLeave(ByVal sender As Object, ByVal e As MouseEventArgs)
' Cast the source of the event to a Button.
Dim source As Button = TryCast(e.Source, Button)
' If source is a Button.
If source IsNot Nothing Then
source.Background = Brushes.AliceBlue
End If
End Sub
Entrada de texto
O evento TextInput permite que você ouça a entrada de texto de uma maneira independente do dispositivo. O teclado é o principal meio de entrada de texto, mas fala, caligrafia e outros dispositivos de entrada também podem gerar entrada de texto.
Para entrada de teclado, o WPF primeiro envia os eventos KeyDown/KeyUp apropriados. Se esses eventos não forem manipulados e a tecla for textual (em vez de uma tecla de controle, como setas direcionais ou teclas de função), um evento TextInput será gerado. Nem sempre há um mapeamento simples um-para-um entre eventos KeyDown,/,KeyUp e TextInput, porque várias teclas pressionadas podem gerar um único caractere de entrada de texto e pressionamentos de teclas únicas podem gerar sequências de vários caracteres. Isso é especialmente verdadeiro para idiomas como chinês, japonês e coreano, que usam IMEs (Input Method Editors) para gerar os milhares de caracteres possíveis em seus alfabetos correspondentes.
Quando o WPF envia um evento KeyUp/KeyDown, Key é configurado para Key.System caso as teclas possam fazer parte de um evento TextInput (se ALT+S forem pressionadas, por exemplo). Isso permite que o código num manipulador de eventos KeyDown verifique a existência de Key.System e, caso seja encontrado, deixe o processamento para o manipulador do evento TextInput subsequentemente gerado. Nesses casos, as várias propriedades do argumento TextCompositionEventArgs podem ser usadas para determinar as teclas pressionadas originalmente. Da mesma forma, se um IME estiver ativo, Key terá o valor de Key.ImeProcessede ImeProcessedKey indicará o ou os pressionamentos de tecla originais.
O exemplo a seguir define um manipulador para o evento Click e um manipulador para o evento KeyDown.
O primeiro segmento de código ou marcação cria a interface do usuário.
<StackPanel KeyDown="OnTextInputKeyDown">
<Button Click="OnTextInputButtonClick"
Content="Open" />
<TextBox> . . . </TextBox>
</StackPanel>
// Create the UI elements.
StackPanel textInputStackPanel = new StackPanel();
Button textInputeButton = new Button();
TextBox textInputTextBox = new TextBox();
textInputeButton.Content = "Open";
// Attach elements to StackPanel.
textInputStackPanel.Children.Add(textInputeButton);
textInputStackPanel.Children.Add(textInputTextBox);
// Attach event handlers.
textInputStackPanel.KeyDown += new KeyEventHandler(OnTextInputKeyDown);
textInputeButton.Click += new RoutedEventHandler(OnTextInputButtonClick);
' Create the UI elements.
Dim textInputStackPanel As New StackPanel()
Dim textInputeButton As New Button()
Dim textInputTextBox As New TextBox()
textInputeButton.Content = "Open"
' Attach elements to StackPanel.
textInputStackPanel.Children.Add(textInputeButton)
textInputStackPanel.Children.Add(textInputTextBox)
' Attach event handlers.
AddHandler textInputStackPanel.KeyDown, AddressOf OnTextInputKeyDown
AddHandler textInputeButton.Click, AddressOf OnTextInputButtonClick
O segundo segmento de código contém os manipuladores de eventos.
private void OnTextInputKeyDown(object sender, KeyEventArgs e)
{
if (e.Key == Key.O && Keyboard.Modifiers == ModifierKeys.Control)
{
handle();
e.Handled = true;
}
}
private void OnTextInputButtonClick(object sender, RoutedEventArgs e)
{
handle();
e.Handled = true;
}
public void handle()
{
MessageBox.Show("Pretend this opens a file");
}
Private Sub OnTextInputKeyDown(ByVal sender As Object, ByVal e As KeyEventArgs)
If e.Key = Key.O AndAlso Keyboard.Modifiers = ModifierKeys.Control Then
handle()
e.Handled = True
End If
End Sub
Private Sub OnTextInputButtonClick(ByVal sender As Object, ByVal e As RoutedEventArgs)
handle()
e.Handled = True
End Sub
Public Sub handle()
MessageBox.Show("Pretend this opens a file")
End Sub
Como os eventos de entrada se propagam pela rota do evento, o StackPanel recebe o evento de entrada independentemente de qual elemento tem o foco no teclado. O controle TextBox é notificado primeiro e o manipulador de OnTextInputKeyDown
é chamado somente se o TextBox não manipulou a entrada. Se o evento PreviewKeyDown for usado em vez do evento KeyDown, o manipulador de OnTextInputKeyDown
será chamado primeiro.
Neste exemplo, a lógica de manipulação é gravada duas vezes: uma vez para CTRL+O e outra para o evento de clique do botão. Isso pode ser simplificado usando comandos, em vez de manipular os eventos de entrada diretamente. Os comandos são discutidos nesta visão geral e na Visão geral de comandos.
Toque e Manipulação
O novo hardware e API no sistema operacional Windows 7 fornecem aos aplicativos a capacidade de receber entrada de vários toques simultaneamente. O WPF permite que os aplicativos detetem e respondam ao toque de maneira semelhante à resposta a outras entradas, como o mouse ou o teclado, gerando eventos quando o toque ocorre.
O WPF expõe dois tipos de eventos quando o toque ocorre: eventos de toque e eventos de manipulação. Os eventos de toque fornecem dados brutos sobre cada dedo em uma tela sensível ao toque e seu movimento. Os eventos de manipulação interpretam a entrada como determinadas ações. Ambos os tipos de eventos são discutidos nesta seção.
Pré-requisitos
Você precisa dos seguintes componentes para desenvolver um aplicativo que responda ao toque.
Visual Studio 2010.
Windows 7.
Um dispositivo, como um ecrã tátil, que suporta o Windows Touch.
Terminologia
Os termos a seguir são usados quando o toque é discutido.
Touch é um tipo de entrada de usuário que é reconhecido pelo Windows 7. Normalmente, o toque é iniciado colocando os dedos em uma tela sensível ao toque. Observe que dispositivos como um touchpad que é comum em laptops não suportam toque se o dispositivo apenas converte a posição e o movimento do dedo como entrada do mouse.
Multitouch é o toque que ocorre em mais de um ponto simultaneamente. Windows 7 e WPF suporta multitouch. Sempre que o toque é discutido na documentação do WPF, os conceitos se aplicam ao multitouch.
Uma manipulação ocorre quando o toque é interpretado como uma ação física que é aplicada a um objeto. No WPF, os eventos de manipulação interpretam a entrada como uma tradução, expansão ou manipulação de rotação.
Um
touch device
representa um dispositivo que produz entrada por toque, como um único dedo em uma tela sensível ao toque.
Controles que respondem ao toque
Os controles a seguir podem ser rolados arrastando um dedo pelo controle se ele tiver conteúdo que está rolado para fora da exibição.
O ScrollViewer define a propriedade ScrollViewer.PanningMode anexada que permite especificar se o movimento panorâmico por toque está habilitado horizontalmente, verticalmente, ambos ou nenhum. A propriedade ScrollViewer.PanningDeceleration especifica a rapidez com que a rolagem diminui quando o usuário levanta o dedo da tela sensível ao toque. A propriedade anexada ScrollViewer.PanningRatio especifica a proporção do deslocamento de rolagem para o deslocamento de manipulação translate.
Toque em Eventos
As classes base, UIElement, UIElement3De ContentElement, definem eventos que você pode assinar para que seu aplicativo responda ao toque. Os eventos de toque são úteis quando seu aplicativo interpreta o toque como algo diferente da manipulação de um objeto. Por exemplo, um aplicativo que permite que um usuário desenhe com um ou mais dedos assinaria eventos de toque.
Todas as três classes definem os seguintes eventos, que se comportam de forma semelhante, independentemente da classe definidora.
Tal como os eventos de teclado e rato, os eventos de toque são eventos roteados. Os eventos que começam com Preview
são eventos de tunelamento e os eventos que começam com Touch
são eventos borbulhantes. Para obter mais informações sobre eventos roteados, consulte Visão Geral de Eventos Roteados. Ao manipular esses eventos, você pode obter a posição da entrada, em relação a qualquer elemento, chamando o método GetTouchPoint ou GetIntermediateTouchPoints.
Para entender a interação entre os eventos de toque, considere o cenário em que um usuário coloca um dedo em um elemento, move o dedo no elemento e, em seguida, levanta o dedo do elemento. A ilustração a seguir mostra a execução dos eventos borbulhantes (os eventos de tunelamento são omitidos para simplificar).
Eventos de toque
A lista a seguir descreve a sequência dos eventos na ilustração anterior.
O evento TouchEnter ocorre uma vez quando o usuário coloca o dedo no elemento.
O evento TouchDown ocorre uma vez.
O evento TouchMove ocorre várias vezes à medida que o usuário move o dedo dentro do elemento .
O evento TouchUp ocorre uma vez quando o usuário levanta o dedo do elemento.
O evento TouchLeave ocorre uma vez.
Quando são utilizados mais de dois dedos, os acontecimentos ocorrem para cada dedo.
Eventos de manipulação
Para casos em que um aplicativo permite que um usuário manipule um objeto, a classe UIElement define eventos de manipulação. Ao contrário dos eventos de toque que simplesmente relatam a posição do toque, os eventos de manipulação relatam como a entrada pode ser interpretada. Existem três tipos de manipulações, translação, expansão e rotação. A lista a seguir descreve como invocar os três tipos de manipulações.
Coloque o dedo num objeto e mova o dedo pelo ecrã tátil para invocar uma manipulação de tradução. Isso geralmente move o objeto.
Coloque dois dedos em um objeto e mova os dedos mais próximos ou mais distantes um do outro para invocar uma manipulação de expansão. Isso geralmente redimensiona o objeto.
Coloque dois dedos em um objeto e gire os dedos um ao redor do outro para invocar uma manipulação de rotação. Isso geralmente gira o objeto.
Mais de um tipo de manipulação pode ocorrer simultaneamente.
Quando você faz com que os objetos respondam a manipulações, você pode fazer com que o objeto pareça ter inércia. Isso pode fazer com que seus objetos simulem o mundo físico. Por exemplo, quando você empurra um livro sobre uma mesa, se você forçar o suficiente, o livro continuará a se mover depois que você lançá-lo. O WPF permite que você simule esse comportamento gerando eventos de manipulação depois que os dedos do usuário liberam o objeto.
Para obter informações sobre como criar um aplicativo que permite ao usuário mover, redimensionar e girar um objeto, consulte Passo a passo: Criando seu aplicativo de primeiro toque.
O UIElement define os seguintes eventos de manipulação.
Por padrão, um UIElement não recebe esses eventos de manipulação. Para receber eventos de manipulação num UIElement, configure UIElement.IsManipulationEnabled para true
.
O caminho de execução de eventos de manipulação
Considere um cenário em que um usuário "lança" um objeto. O usuário coloca um dedo no objeto, move o dedo através da tela sensível ao toque por uma curta distância e, em seguida, levanta o dedo enquanto ele está em movimento. O resultado disso é que o objeto se moverá sob o dedo do usuário e continuará a se mover depois que o usuário levantar o dedo.
A ilustração a seguir mostra o caminho de execução de eventos de manipulação e informações importantes sobre cada evento.
Eventos de manipulação
A lista a seguir descreve a sequência dos eventos na ilustração anterior.
O evento ManipulationStarting ocorre quando o usuário coloca um dedo no objeto. Entre outras coisas, esse evento permite que você defina a propriedade ManipulationContainer. Nos eventos subsequentes, a posição da manipulação será relativa ao ManipulationContainer. Em eventos diferentes de ManipulationStarting, essa propriedade é somente leitura, portanto, o evento ManipulationStarting é o único momento em que você pode definir essa propriedade.
O evento ManipulationStarted ocorre em seguida. Este evento relata a origem da manipulação.
O evento ManipulationDelta ocorre várias vezes quando os dedos de um usuário se movem em uma tela sensível ao toque. A propriedade DeltaManipulation da classe ManipulationDeltaEventArgs informa se a manipulação é interpretada como movimento, expansão ou tradução. É aqui que você executa a maior parte do trabalho de manipulação de um objeto.
O evento ManipulationInertiaStarting ocorre quando os dedos do usuário perdem contato com o objeto. Este evento permite especificar a desaceleração das manipulações durante a inércia. Isso é para que seu objeto possa emular diferentes espaços físicos ou atributos, se você escolher. Por exemplo, suponha que seu aplicativo tenha dois objetos que representam itens no mundo físico e um seja mais pesado que o outro. Você pode fazer o objeto mais pesado desacelerar mais rápido do que o objeto mais leve.
O evento ManipulationDelta ocorre várias vezes à medida que ocorre a inércia. Observe que esse evento ocorre quando os dedos do usuário se movem pela tela sensível ao toque e quando o WPF simula inércia. Em outras palavras, ManipulationDelta ocorre antes e depois do evento ManipulationInertiaStarting. A propriedade ManipulationDeltaEventArgs.IsInertial informa se o evento ManipulationDelta ocorre durante a inércia, para que você possa verificar essa propriedade e executar ações diferentes, dependendo de seu valor.
O evento ManipulationCompleted ocorre quando a manipulação e qualquer inércia terminam. Ou seja, depois de todos os eventos ManipulationDelta ocorrerem, o evento ManipulationCompleted ocorre para sinalizar que a manipulação está completa.
O UIElement também define o evento ManipulationBoundaryFeedback. Esse evento ocorre quando o método ReportBoundaryFeedback é chamado no evento ManipulationDelta. O evento ManipulationBoundaryFeedback permite que aplicativos ou componentes forneçam feedback visual quando um objeto atinge um limite. Por exemplo, a classe Window manipula o evento ManipulationBoundaryFeedback para fazer com que a janela se mova ligeiramente quando sua borda é encontrada.
Você pode cancelar a manipulação chamando o método Cancel nos argumentos de evento em qualquer evento de manipulação, exceto ManipulationBoundaryFeedback evento. Quando você chama Cancel, os eventos de manipulação não são mais gerados e os eventos do mouse ocorrem por toque. A tabela a seguir descreve a relação entre o momento em que a manipulação é cancelada e os eventos de mouse que ocorrem.
O evento em que a função Cancelar é invocada | Os eventos do mouse que ocorrem devido a entradas que já ocorreram |
---|---|
ManipulationStarting e ManipulationStarted | Eventos com o mouse para baixo. |
ManipulationDelta | Mouse para baixo e eventos de movimentação do mouse. |
ManipulationInertiaStarting e ManipulationCompleted | Eventos do mouse para baixo, movimento do mouse e mouse para cima. |
Observe que, se você chamar Cancel quando a manipulação estiver na inércia, o método retornará false
e a entrada não gerará eventos do mouse.
A relação entre o toque e os eventos de manipulação
Um UIElement sempre pode receber eventos de toque. Quando a propriedade IsManipulationEnabled é definida como true
, um UIElement pode receber eventos de toque e manipulação. Se o evento TouchDown não é tratado (ou seja, a propriedade Handled é false
), a lógica de manipulação captura o toque no elemento e gera os eventos de manipulação. Se a propriedade Handled estiver definida como true
no evento TouchDown, a lógica de manipulação não gerará eventos de manipulação. A ilustração a seguir mostra a relação entre eventos de toque e eventos de manipulação.
Eventos de toque e manipulação
A lista a seguir descreve a relação entre os eventos de toque e manipulação mostrada na ilustração anterior.
Quando o primeiro dispositivo de toque gera um evento TouchDown em um UIElement, a lógica de manipulação chama o método CaptureTouch, que gera o evento GotTouchCapture.
Quando o GotTouchCapture ocorre, a lógica de manipulação chama o método Manipulation.AddManipulator, que gera o evento ManipulationStarting.
Quando os eventos TouchMove ocorrem, a lógica de manipulação gera os eventos ManipulationDelta que ocorrem antes do evento ManipulationInertiaStarting.
Quando o último dispositivo de toque no elemento gera o evento TouchUp, a lógica de manipulação gera o evento ManipulationInertiaStarting.
Foco
Existem dois conceitos principais que pertencem ao foco no WPF: foco do teclado e foco lógico.
Foco do teclado
O foco do teclado refere-se ao elemento que está recebendo a entrada do teclado. Pode haver apenas um elemento em toda a área de trabalho que tem foco no teclado. No WPF, o elemento que tem foco no teclado terá IsKeyboardFocused definido como true
. O método estático KeyboardFocusedElement retorna o elemento que atualmente tem o foco do teclado.
O foco do teclado pode ser obtido ao navegar pelos elementos com a tecla Tab ou ao clicar com o rato em determinados elementos, como por exemplo um TextBox. O foco do teclado também pode ser obtido programaticamente usando o método Focus na classe Keyboard. Focus tenta atribuir o foco do teclado ao elemento especificado. O elemento retornado por Focus é o elemento que atualmente tem foco no teclado.
Para que um elemento obtenha o foco do teclado, a propriedade Focusable e as propriedades IsVisible devem ser definidas como true. Algumas classes, como Panel, têm Focusable definidas como false
por padrão; Portanto, talvez seja necessário definir essa propriedade como true
se quiser que esse elemento seja capaz de obter foco.
O exemplo a seguir usa Focus para definir o foco do teclado em um Button. O local recomendado para definir o foco inicial em um aplicativo é no manipulador de eventos Loaded.
private void OnLoaded(object sender, RoutedEventArgs e)
{
// Sets keyboard focus on the first Button in the sample.
Keyboard.Focus(firstButton);
}
Private Sub OnLoaded(ByVal sender As Object, ByVal e As RoutedEventArgs)
' Sets keyboard focus on the first Button in the sample.
Keyboard.Focus(firstButton)
End Sub
Para obter mais informações sobre o foco do teclado, consulte Visão geral do foco .
Foco lógico
Foco lógico refere-se ao FocusManager.FocusedElement em um escopo de foco. Pode haver vários elementos que têm foco lógico em um aplicativo, mas pode haver apenas um elemento que tem foco lógico em um escopo de foco específico.
Um escopo de foco é um elemento de contentor que acompanha o FocusedElement dentro do seu âmbito. Quando o foco deixa um escopo de foco, o elemento focado perderá o foco do teclado, mas manterá o foco lógico. Quando o foco retorna ao escopo do foco, o elemento focado obterá o foco do teclado. Isso permite que o foco do teclado seja alterado entre vários escopos de foco, mas garante que o elemento focado dentro do escopo de foco permaneça o elemento focado quando o foco retorna.
Um elemento pode ser convertido em um âmbito de foco em Extensible Application Markup Language (XAML) ao definir a propriedade anexada FocusManagerIsFocusScope como true
, ou em código ao definir a propriedade anexada usando o método SetIsFocusScope.
O exemplo a seguir transforma um StackPanel em um escopo de foco definindo a propriedade IsFocusScope anexada.
<StackPanel Name="focusScope1"
FocusManager.IsFocusScope="True"
Height="200" Width="200">
<Button Name="button1" Height="50" Width="50"/>
<Button Name="button2" Height="50" Width="50"/>
</StackPanel>
StackPanel focuseScope2 = new StackPanel();
FocusManager.SetIsFocusScope(focuseScope2, true);
Dim focuseScope2 As New StackPanel()
FocusManager.SetIsFocusScope(focuseScope2, True)
As classes no WPF que são escopos de foco por padrão são Window, Menu, ToolBare ContextMenu.
Um elemento que tem foco de teclado também terá foco lógico para o escopo de foco ao qual pertence; assim, definir o foco em um elemento com o método Focus na classe Keyboard ou nas classes de elemento base tentará dar ao elemento foco de teclado e foco lógico.
Para determinar o elemento focalizado em um escopo de foco, use GetFocusedElement. Para alterar o elemento em foco para um escopo de foco, use SetFocusedElement.
Para obter mais informações sobre foco lógico, consulte Visão geral do foco .
Posição do mouse
A API de entrada do WPF fornece informações úteis em relação aos espaços de coordenadas. Por exemplo, a coordenada (0,0)
é a coordenada superior esquerda, mas a parte superior esquerda de qual elemento da árvore? O elemento que é o alvo de entrada? O elemento ao qual você anexou seu manipulador de eventos? Ou outra coisa? Para evitar confusão, a API de entrada do WPF requer que você especifique seu quadro de referência quando trabalhar com coordenadas obtidas através do mouse. O método GetPosition retorna a coordenada do ponteiro do mouse em relação ao elemento especificado.
Captura do mouse
Os dispositivos de mouse possuem especificamente uma característica modal conhecida como captura de mouse. A captura do mouse é usada para manter um estado de entrada de transição quando uma operação de arrastar e soltar é iniciada, de modo que outras operações envolvendo a posição nominal na tela do ponteiro do mouse não ocorram necessariamente. Durante o arrasto, o usuário não pode clicar sem abortar o recurso de arrastar e soltar, o que torna a maioria das dicas do mouse inadequadas enquanto a captura do mouse é mantida pela origem do arrasto. O sistema de entrada expõe APIs que podem determinar o estado de captura do mouse, bem como APIs que podem forçar a captura do mouse para um elemento específico ou limpar o estado de captura do mouse. Para obter mais informações sobre operações de arrastar e soltar, consulte Visão geral de arrastar e soltar.
Comandos
Os comandos permitem a manipulação de entrada em um nível mais semântico do que a entrada do dispositivo. Os comandos são diretivas simples, como Cut
, Copy
, Paste
ou Open
. Os comandos são úteis para centralizar sua lógica de comando. O mesmo comando pode ser acedido a partir de um Menu, num ToolBarou através de um atalho de teclado. Os comandos também fornecem um mecanismo para desativar os controles quando o comando fica indisponível.
RoutedCommand é a implementação WPF do ICommand. Quando um RoutedCommand é executado, são gerados um PreviewExecuted e um evento Executed no destino do comando, os quais se propagam de forma hierárquica e expansiva através da árvore de elementos como outras entradas. Se um destino de comando não estiver definido, o elemento com foco no teclado será o destino do comando. A lógica que executa o comando é anexada a um CommandBinding. Quando um evento Executed chega a um CommandBinding para esse comando específico, o ExecutedRoutedEventHandler no CommandBinding é acionado. Este manipulador executa a ação do comando.
Para obter mais informações sobre comandos, consulte Visão geral do comando .
WPF fornece uma biblioteca de comandos comuns que consiste em ApplicationCommands, MediaCommands, ComponentCommands, NavigationCommandse EditingCommands, ou você pode definir o seu próprio.
O exemplo a seguir mostra como configurar um MenuItem para que, quando ele for clicado, ele invoque o comando Paste no TextBox, supondo que o TextBox tenha foco no teclado.
<StackPanel>
<Menu>
<MenuItem Command="ApplicationCommands.Paste" />
</Menu>
<TextBox />
</StackPanel>
// Creating the UI objects
StackPanel mainStackPanel = new StackPanel();
TextBox pasteTextBox = new TextBox();
Menu stackPanelMenu = new Menu();
MenuItem pasteMenuItem = new MenuItem();
// Adding objects to the panel and the menu
stackPanelMenu.Items.Add(pasteMenuItem);
mainStackPanel.Children.Add(stackPanelMenu);
mainStackPanel.Children.Add(pasteTextBox);
// Setting the command to the Paste command
pasteMenuItem.Command = ApplicationCommands.Paste;
// Setting the command target to the TextBox
pasteMenuItem.CommandTarget = pasteTextBox;
' Creating the UI objects
Dim mainStackPanel As New StackPanel()
Dim pasteTextBox As New TextBox()
Dim stackPanelMenu As New Menu()
Dim pasteMenuItem As New MenuItem()
' Adding objects to the panel and the menu
stackPanelMenu.Items.Add(pasteMenuItem)
mainStackPanel.Children.Add(stackPanelMenu)
mainStackPanel.Children.Add(pasteTextBox)
' Setting the command to the Paste command
pasteMenuItem.Command = ApplicationCommands.Paste
Para obter mais informações sobre comandos no WPF, consulte Visão geral de comandos.
O sistema de entrada e os elementos de base
Eventos de entrada, como os eventos anexados definidos pelas classes Mouse, Keyboarde Stylus, são gerados pelo sistema de entrada e injetados em uma posição específica no modelo de objeto com base no teste de acerto da árvore visual em tempo de execução.
Cada um dos eventos que Mouse, Keyboarde Stylus definem como um evento anexado também é reexposto pelas classes de elemento base UIElement e ContentElement como um novo evento roteado. Os eventos roteados do elemento base são gerados por classes que manipulam o evento anexado original e reutilizam os dados do evento.
Quando o evento de entrada se torna associado a um determinado elemento de origem por meio de sua implementação de evento de entrada de elemento base, ele pode ser roteado pelo restante de uma rota de evento baseada em uma combinação de objetos de árvore lógica e visual e ser manipulado pelo código do aplicativo. Geralmente, é mais conveniente manipular esses eventos de entrada relacionados ao dispositivo usando os eventos roteados em UIElement e ContentElement, porque você pode usar uma sintaxe de manipulador de eventos mais intuitiva tanto em XAML quanto em código. Você poderia optar por manipular o evento anexado que iniciou o processo, mas enfrentaria vários problemas: o evento anexado pode ser marcado como manipulado pela manipulação da classe base do elemento, e você precisa usar métodos de acesso em vez da sintaxe verdadeira de eventos para anexar manipuladores aos eventos anexados.
O que vem a seguir
Agora você tem várias técnicas para lidar com a entrada no WPF. Você também deve ter uma melhor compreensão dos vários tipos de eventos de entrada e dos mecanismos de eventos roteados usados pelo WPF.
Recursos adicionais estão disponíveis para explicar os elementos da estrutura do WPF e o roteamento de eventos com mais detalhes. Consulte as seguintes visões gerais para obter mais informações: Visão geral de comando, Visão geral do foco, Visão geral dos elementos básicos, Árvores no WPFe Visão geral dos eventos encaminhados.
Ver também
- Visão Geral do Focus
- Visão geral do comando
- Visão geral de Eventos Roteados
- Visão geral dos elementos básicos do
- Propriedades
.NET Desktop feedback