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 primária da API de entrada é encontrada nas classes de elemento base: UIElement, , ContentElementFrameworkElemente FrameworkContentElement. Para obter mais informações sobre os elementos base, consulte Visão geral de elementos base. Essas classes fornecem funcionalidade para eventos de entrada relacionados a pressionamentos de tecla, 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 KeyDown eventos e PreviewKeyDown . A diferença nesses eventos está em como eles são roteados para o elemento de destino. Eventos de visualização são roteados por túnel pela árvore de elementos, do elemento raiz ao elemento de destino. Eventos por propagação propagam-se para cima, do elemento de destino até o elemento raiz. O roteamento de eventos no WPF é discutido com mais detalhes posteriormente nesta visão geral e na Visão geral de eventos roteados.

Classes de mouse e teclado

Além da API de entrada nas classes de elemento base, a classe e as Keyboard classes fornecem API adicional para trabalhar com entrada de teclado e Mouse mouse.

Exemplos de API de entrada na Keyboard classe são a Modifiers propriedade, que retorna o pressionado no momento, e o ModifierKeysIsKeyDown método, que determina se uma tecla especificada é pressionada.

O exemplo a seguir usa o método para determinar se a GetKeyStatesKey está no estado inativo.

// 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 Mouse classe são MiddleButton, que obtém o estado do botão do meio do mouse e DirectlyOver, que obtém o elemento que o ponteiro do mouse está no momento.

O exemplo a seguir determina se o LeftButton no mouse está no Pressed estado.

if (Mouse.LeftButton == MouseButtonState.Pressed)
{
    UpdateSampleResults("Left Button Pressed");
}
If Mouse.LeftButton = MouseButtonState.Pressed Then
    UpdateSampleResults("Left Button Pressed")
End If

As Mouse classes e Keyboard são abordadas com mais detalhes ao longo desta visão geral.

Entrada de caneta

WPF integrou o suporte para o Stylus. A Stylus é uma entrada de caneta popularizada 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 de caneta que usa um modelo semelhante ao teclado e ao mouse. Todas as APIs relacionadas à caneta contêm a palavra "Stylus".

Já que a caneta pode atuar como um mouse, aplicativos que dão suporte apenas à entrada de mouse ainda podem obter algum nível de suporte à caneta automaticamente. Quando a caneta é usada desse modo, o aplicativo tem a oportunidade de manipular o evento de caneta apropriado e, em seguida, manipular o evento de mouse correspondente. Além disso, os serviços de alto nível, por exemplo, a entrada de tinta, também estão disponíveis por meio da abstração do dispositivo de caneta. Para obter mais informações sobre a tinta como entrada, consulte Introdução à tinta.

Roteamento de eventos

A FrameworkElement pode conter outros elementos como elementos filho em seu modelo de conteúdo, formando uma árvore de elementos. No WPF, o elemento pai pode participar de entradas direcionadas a seus elementos filho 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.

Roteamento de eventos é o processo de encaminhamento de eventos para vários elementos para 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 possa ter sido originado de um elemento diferente. Eventos roteados usam um de três mecanismos de roteamento: direto, por propagação e por túnel. No roteamento direto, o elemento de origem é o único elemento notificado e o evento não será 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 roteamento por propagação ocorre de baixo para cima na árvore de elementos, notificando primeiro o elemento que originou o evento, depois o elemento pai e assim por diante. O roteamento por túnel começa na raiz da árvore de elementos prossegue de cima para baixo, terminando com o elemento de origem original. Para obter mais informações sobre os 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 encapsulamento e um evento borbulhante. Eventos por túnel são diferenciados dos eventos por propagação com o prefixo "Preview". Por exemplo, PreviewMouseMove é a versão de encapsulamento de um evento de movimentação 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 WPF de entrada em Visão geral de eventos roteados.

Manipulação de eventos de entrada

Para receber a entrada em um elemento, um manipulador de eventos deve estar 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, você deverá definir 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.

Eventos de teclado ocorrem quando o sistema operacional relata ações de tecla que ocorrem enquanto o foco do teclado está em um elemento. Tanto eventos de mouse quanto de caneta podem ser divididos em duas categorias: eventos relatam alterações na posição do ponteiro com relação ao elemento e eventos que relatam alterações no estado dos botões do dispositivo.

Exemplo de evento de entrada do teclado

O exemplo a seguir escuta um pressionamento de tecla de seta para a esquerda. É criado um que tem um StackPanelButtonarquivo . Um manipulador de eventos para escutar o pressionamento da tecla de seta para a esquerda é anexado Button à instância.

A primeira seção do exemplo cria o e o e anexa o manipulador de eventos para o StackPanelButtonKeyDown.

<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 tecla de seta para a esquerda é pressionada e o foco do teclado tem o Button manipulador é executado e a Background cor do Button é alterada. Se a tecla for pressionada, mas não for a tecla de seta para a esquerda, a Background cor do Button é alterada de volta para 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 de a BackgroundButton é alterada quando o ponteiro do mouse insere o Button. A Background cor é restaurada quando o mouse deixa o Button.

A primeira seção do exemplo cria o StackPanel controle e e anexa os manipuladores de eventos para os MouseEnter eventos e ButtonMouseLeave 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 Background cor do Button é alterada para SlateGray. Quando o mouse sai do Button, a Background cor 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 TextInput evento permite que você escute a entrada de texto de maneira independente do dispositivo. O teclado é o método primário de entrada de texto; no entanto, fala, manuscrito e outros dispositivos de entrada também podem gerar entrada de texto.

Para entrada de teclado, o WPF primeiro envia os eventos apropriados KeyDown/KeyUp . Se esses eventos não forem manipulados e a chave for textual (em vez de uma tecla de controle, como setas direcionais ou teclas de função), um TextInput evento será gerado. Nem sempre há um mapeamento simples de um para um entre e TextInput eventos, porque vários pressionamentos de tecla podem gerar um único caractere de entrada de texto e pressionamentos deKeyUpKeyDown/tecla únicos podem gerar cadeias de caracteres 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, é definido como se os pressionamentos de tecla podem se tornar parte de um KeyUp/TextInputKeyDown evento (se ALT+S for pressionado, Key por exemplo).Key.System Isso permite que o código em um KeyDown manipulador de eventos verifique Key.System e, se encontrado, deixe o processamento para o manipulador do evento gerado TextInput subsequentemente. Nesses casos, as várias propriedades do argumento podem ser usadas para determinar os pressionamentos de TextCompositionEventArgs tecla originais. Da mesma forma, se um IME estiver ativo, tiver o valor de , Key e ImeProcessedKey fornecer o pressionamento de tecla ou pressionamentos de Key.ImeProcessedtecla originais.

O exemplo a seguir define um manipulador para o evento e um manipulador para o ClickKeyDown evento.

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 borbulham a rota do evento, o StackPanel recebe a entrada independentemente de qual elemento tem foco no teclado. O TextBox controle é notificado primeiro e o manipulador é chamado somente se o OnTextInputKeyDownTextBox não manipulou a entrada. Se o evento for usado em vez do KeyDown evento, o OnTextInputKeyDownPreviewKeyDown manipulador será chamado primeiro.

Neste exemplo, a lógica de tratamento é gravada duas vezes – uma vez para CTRL + O e novamente para o evento de clique do botão. Isso pode ser simplificado usando comandos em vez de manipular os eventos de entrada diretamente. Comandos são discutidos nesta visão geral e na Visão geral dos comandos.

Toque e manipulação

Novo hardware e a API no sistema operacional Windows 7 fornecem a aplicativos a capacidade de receber entradas de vários toques simultaneamente. O WPF permite que os aplicativos detectem 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. Eventos de toque fornecem dados brutos sobre cada dedo e seu movimento em uma tela touch. 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ê precisará dos componentes a seguir para desenvolver um aplicativo que responde ao toque.

  • Visual Studio 2010.

  • Windows 7.

  • Um dispositivo, como uma tela touch, que dê suporte a Windows Touch.

Terminologia

Os termos a seguir são usados quando o toque é discutido.

  • Toque é um tipo de entrada do usuário que é reconhecida pelo Windows 7. Geralmente o toque é iniciado colocando-se os dedos em uma tela sensível ao toque. Observe que dispositivos como um touchpad, comuns em computadores laptop, não dão suporte ao toque se o dispositivo simplesmente converte a posição e movimentação do dedo como entrada de mouse.

  • Multitoque é toque que ocorre em mais de um ponto, simultaneamente. O Windows 7 e o WPF suportam multitoque. Sempre que o toque é discutido na documentação do WPF, os conceitos se aplicam ao multitoque.

  • 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 manipulação de tradução, expansão ou rotação.

  • Um touch device representa um dispositivo que produz a entrada de toque, por exemplo, um único dedo em uma tela touch.

Controles que respondem ao toque

É possível rolar pelos controles a seguir arrastando um dedo pelo controle, caso ele tenha conteúdo que está fora da exibição.

O ScrollViewer define a propriedade anexada que permite especificar se o ScrollViewer.PanningMode movimento panorâmico por toque está habilitado horizontalmente, verticalmente, ambos ou nenhum dos dois. A ScrollViewer.PanningDeceleration propriedade especifica a rapidez com que a rolagem fica mais lenta quando o usuário levanta o dedo da tela sensível ao toque. A ScrollViewer.PanningRatio propriedade attached especifica a proporção de deslocamento de rolagem para converter o deslocamento de manipulação.

Eventos de Toque

As classes base, , e ContentElement, UIElementUIElement3Ddefinem eventos que você pode assinar para que seu aplicativo responda ao toque. Eventos de toque são úteis quando seu aplicativo interpreta toque como algo diferente de manipular 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 eventos a seguir, que se comportam da mesma forma independentemente da classe que os define.

Assim como os eventos de teclado e mouse, os eventos de toque são eventos roteados. Os eventos que começam com Preview são eventos por túnel e os eventos que começam com Touch são eventos por propagação. Para obter mais informações sobre os eventos roteados, consulte Visão geral de eventos roteados. Ao manipular esses eventos, você pode obter a posição da entrada, relativa a qualquer elemento, chamando o GetTouchPoint método ou GetIntermediateTouchPoints .

Para compreender 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 pelo elemento e, em seguida, levanta o dedo do elemento. A ilustração a seguir mostra a execução dos eventos por propagação (os eventos por túnel são omitidos por questão de simplicidade).

The sequence of touch events. Eventos de toque

A lista a seguir descreve a sequência de eventos na ilustração anterior.

  1. O TouchEnter evento ocorre uma vez quando o usuário coloca um dedo no elemento.

  2. O TouchDown evento ocorre uma vez.

  3. O TouchMove evento ocorre várias vezes à medida que o usuário move o dedo dentro do elemento .

  4. O TouchUp evento ocorre uma vez quando o usuário levanta o dedo do elemento.

  5. O TouchLeave evento ocorre uma vez.

Quando mais de dois dedos são usados, os eventos ocorrem para cada dedo.

Eventos de Manipulação

Para casos em que um aplicativo permite que um usuário manipule um objeto, a UIElement classe define eventos de manipulação. Diferentemente de eventos de toque que simplesmente relatam a posição do toque, os eventos de manipulação relatam como a entrada pode ser interpretada. Há três tipos de manipulação: rotação, translação e expansão. A lista a seguir descreve como invocar os três tipos de manipulação.

  • Coloque um dedo em um objeto e mova o dedo na tela touch para invocar uma manipulação de translação. Geralmente, isso 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 em torno um do outro para invocar uma manipulação de rotação. Isso geralmente gira o objeto.

É possível que mais de um tipo de manipulação ocorram simultaneamente.

Quando você faz com que 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 por uma mesa, o livro continua a mover-se depois de você liberá-lo, caso você o empurre com força suficiente. 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 que o usuário mova, redimensione e gire um objeto, consulte Passo a passo: criar seu primeiro aplicativo de toque.

O UIElement define os seguintes eventos de manipulação.

Por padrão, a UIElement não recebe esses eventos de manipulação. Para receber eventos de manipulação em um UIElement, defina UIElement.IsManipulationEnabled como 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 pela tela touch por uma distância curta e, em seguida, levanta o dedo enquanto ele está se movendo. O resultado disso é que o objeto se moverá sob o dedo do usuário e continuará a mover-se 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.

The sequence of manipulation events. Eventos de manipulação

A lista a seguir descreve a sequência de eventos na ilustração anterior.

  1. O ManipulationStarting evento ocorre quando o usuário coloca um dedo no objeto. Entre outras coisas, esse evento permite que você defina a ManipulationContainer propriedade. Nos eventos subsequentes, a posição da manipulação será relativa ao ManipulationContainer. Em eventos diferentes do ManipulationStarting, essa propriedade é somente leitura, portanto, o ManipulationStarting evento é a única vez que você pode definir essa propriedade.

  2. O ManipulationStarted evento ocorre em seguida. Esse evento relata a origem da manipulação.

  3. O ManipulationDelta evento ocorre várias vezes quando os dedos de um usuário se movem em uma tela sensível ao toque. A DeltaManipulation propriedade da classe informa se a manipulação é interpretada ManipulationDeltaEventArgs como movimento, expansão ou tradução. É aqui que você realiza a maior parte do trabalho envolvido na manipulação de um objeto.

  4. O ManipulationInertiaStarting evento ocorre quando os dedos do usuário perdem contato com o objeto. Esse evento permite que você especifique a desaceleração das manipulações durante a inércia. Isso é para que seu objeto possa emular espaços físicos ou atributos diferentes, se você assim escolher. Por exemplo, suponha que seu aplicativo tem dois objetos que representam itens no mundo físico e um deles é mais pesado que o outro. Você pode fazer com que o objeto mais pesado desacelere mais rápido do que o objeto mais leve.

  5. O ManipulationDelta evento ocorre várias vezes à medida que a inércia ocorre. Observe que esse evento ocorre quando os dedos do usuário se movem pela tela sensível ao toque e quando o WPF simula a inércia. Em outras palavras, ManipulationDelta ocorre antes e depois do ManipulationInertiaStarting evento. A ManipulationDeltaEventArgs.IsInertial propriedade informa se o evento ocorre durante a ManipulationDelta inércia, para que você possa verificar essa propriedade e executar ações diferentes, dependendo de seu valor.

  6. O ManipulationCompleted evento ocorre quando a manipulação e qualquer inércia termina. Ou seja, depois que todos os ManipulationDelta eventos ocorrem, o ManipulationCompleted evento ocorre para sinalizar que a manipulação está completa.

O UIElement também define o ManipulationBoundaryFeedback evento. Esse evento ocorre quando o ReportBoundaryFeedback método é chamado no ManipulationDelta evento. O ManipulationBoundaryFeedback evento permite que aplicativos ou componentes forneçam feedback visual quando um objeto atinge um limite. Por exemplo, a classe manipula o evento para fazer com que a janela se mova WindowManipulationBoundaryFeedback ligeiramente quando sua borda é encontrada.

Você pode cancelar a manipulação chamando o Cancel método nos argumentos de evento em qualquer evento de manipulação, exceto ManipulationBoundaryFeedback evento. Quando você chama Cancelo , os eventos de manipulação não são mais gerados e os eventos do mouse ocorrem para toque. A tabela a seguir descreve a relação entre a hora em que a manipulação é cancelada e os eventos de mouse que ocorrem.

O evento no qual Cancel é chamado Os eventos de mouse que ocorrem para entrada e que já ocorreram
ManipulationStarting e ManipulationStarted Eventos de pressionamento do mouse.
ManipulationDelta Eventos de pressionamento do mouse e eventos de movimentação do mouse.
ManipulationInertiaStarting e ManipulationCompleted Pressionamento do mouse, movimentação do mouse e liberação do mouse.

Observe que se você chamar Cancel quando a manipulação estiver em inércia, o método retornará false e a entrada não gerará eventos do mouse.

A relação entre eventos de toque e eventos de manipulação

Um UIElement sempre pode receber eventos de toque. Quando a propriedade é definida como true, a UIElementIsManipulationEnabled pode receber eventos de toque e manipulação. Se o evento não for manipulado (ou seja, a propriedade for false), a Handled lógica de manipulação capturará o TouchDown toque no elemento e gerará os eventos de manipulação. Se a propriedade estiver definida como true no TouchDown evento, a Handled lógica de manipulação não gerará eventos de manipulação. A ilustração a seguir mostra a relação entre os eventos de toque e os eventos de manipulação.

Relationship between touch and manipulation events Eventos de toque e manipulação

A lista a seguir descreve a relação entre os eventos de toque e de manipulação que é mostrada na ilustração anterior.

Foco

Existem dois conceitos principais que dizem respeito ao foco no WPF: foco no teclado e foco lógico.

Foco do teclado

O foco do teclado refere-se ao elemento que está recebendo entrada do teclado. Em toda a área de trabalho, pode haver apenas um elemento que tem o foco do teclado. No WPF, o elemento que tem o foco do teclado terá IsKeyboardFocused definido como true. O método FocusedElement estático Keyboard retorna o elemento que atualmente tem foco no teclado.

O foco do teclado pode ser obtido pressionando a tecla Tab para um elemento ou clicando com o mouse em determinados elementos, como um TextBoxarquivo . O foco do teclado também pode ser obtido programaticamente usando o FocusKeyboard método na classe. Focus tenta dar foco ao teclado do 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 Focusable propriedade e as IsVisible propriedades devem ser definidas como true. Algumas classes, como , foram Focusable definidas como false por padrão, portanto, talvez seja necessário definir essa propriedade como Paneltrue se quiser que esse elemento possa obter foco.

O exemplo a seguir usa Focus para definir o foco do teclado em um Buttonarquivo . O local recomendado para definir o foco inicial em um aplicativo é no manipulador de Loaded eventos.

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 escopo em um foco. Pode haver vários elementos que têm foco lógico em um aplicativo, mas pode haver apenas um elemento com foco lógico em um escopo de foco específico.

Um escopo de foco é um elemento de contêiner que mantém o FocusedElement controle de dentro de seu escopo. Quando o foco deixar um escopo de foco, o elemento com foco perderá o foco do teclado mas manterá o foco lógico. Quando o foco retornar para o escopo de foco, o elemento com foco obterá o foco do teclado. Isso permite que o foco do teclado seja alterado entre vários escopos de foco, mas assegura que o elemento com foco dentro do escopo de foco permanecerá sendo o elemento com foco quando o foco retornar.

Um elemento pode ser transformado em um escopo de foco em XAML (Extensible Application Markup Language) definindo a propriedade anexada como true, ou em código definindo a propriedade IsFocusScope anexada FocusManager usando o SetIsFocusScope método.

O exemplo a seguir transforma um em um StackPanel escopo de foco definindo a IsFocusScope propriedade 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, , MenuToolBare ContextMenu.

Um elemento que tem foco de teclado também terá foco lógico para o escopo de foco ao qual pertence; Portanto, definir o foco em um elemento com o Focus método na Keyboard classe ou as classes de elemento base tentará dar ao elemento Teclado foco e foco lógico.

Para determinar o elemento focado em um escopo de foco, use GetFocusedElement. Para alterar o elemento focado para um escopo de foco, use SetFocusedElement.

Para obter mais informações sobre o 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 trata-se do canto superior esquerdo de qual elemento na árvore? O elemento que é o destino de entrada? O elemento ao qual você anexou o manipulador de eventos? Ou alguma outra coisa? Para evitar confusão, a API de entrada do WPF requer que você especifique seu quadro de referência ao trabalhar com coordenadas obtidas por meio do mouse. O GetPosition método retorna a coordenada do ponteiro do mouse em relação ao elemento especificado.

Captura do mouse

Dispositivos de mouse mantêm especificamente uma característica modal conhecida como captura do mouse. A captura do mouse é usada para manter um estado de entrada de transição quando uma operação do tipo "arrastar e soltar" é iniciada, de modo que outras operações que envolvem a posição nominal do ponteiro do mouse na tela não necessariamente ocorrem. Durante a ação de arrastar, o usuário não poderá clicar sem anular a ação do tipo "arrastar e soltar", o que torna a maioria das indicações mouseover inadequadas; enquanto isso, a captura do mouse é mantida pela origem da ação de arrastar. 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 a um elemento específico ou limpar o estado de captura do mouse. Para obter mais informações sobre operações do tipo "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 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 acessado de um , em um , ou através de um MenuToolBaratalho de teclado. Os comandos também fornecem um mecanismo para desabilitar os controles quando o comando se torna não disponível.

RoutedCommand é a implementação do WPF do ICommand. Quando um é executado, um e um RoutedCommandPreviewExecutedExecuted evento são gerados no destino do comando, que encapsulam e borbulham através da árvore de elementos como outra entrada. Se um destino do comando não for definido, o elemento com o foco do teclado será o destino do comando. A lógica que executa o comando é anexada a um CommandBindingarquivo . Quando um evento atinge um CommandBindingExecuted para esse comando específico, o ExecutedRoutedEventHandler on é CommandBinding chamado. Esse manipulador executa a ação do comando.

Para obter mais informações sobre comandos, consulte Visão geral dos comandos.

O WPF fornece uma biblioteca de comandos comuns que consiste em ApplicationCommands, , , e EditingCommands, MediaCommandsComponentCommandsNavigationCommandsou você pode definir seus próprios.

O exemplo a seguir mostra como configurar um MenuItem para que, quando ele for clicado, ele chame o comando no TextBox, supondo que o Paste foco do TextBox teclado tenha .

<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 elementos base

Eventos de entrada, como os eventos anexados definidos pelas Mouseclasses , e , Keyboardsão gerados pelo sistema de entrada e Stylus injetados em uma posição específica no modelo de objeto com base no teste de ocorrências da árvore visual em tempo de execução.

Cada um dos eventos que Mouse, Keyboarde define como um evento anexado também é reexposto pelas classes UIElement de elemento base e ContentElementStylus como um novo evento roteado. Os eventos roteados de elemento base são gerados por classes que manipulam o evento anexado original e reutilizam os dados do evento.

Quando o evento de entrada passa a ser associado a um elemento de origem específico por meio da implementação de evento de entrada do seu elemento base, ele pode ser roteado pelo restante de uma rota de evento baseada em uma combinação de objetos de árvore visual e lógicos e pode também ser manipulado pelo código do aplicativo. Geralmente, é mais conveniente manipular esses eventos de entrada relacionados ao dispositivo usando os eventos roteados em e ContentElement, porque você pode usar uma sintaxe de manipulador de eventos mais intuitiva tanto em XAML quanto em UIElement código. Em vez disso, você poderia optar por manipular o evento anexado que iniciou o processo, no entanto, você enfrentaria diversos problemas: o evento anexado poderia ser marcado como manipulado pela manipulação de classe do elemento base e, em vez da verdadeira sintaxe de evento, você precisaria usar os métodos acessadores para anexar manipuladores para 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 compreensão aprimorada dos vários tipos de eventos de entrada e dos mecanismos de eventos roteados usados pelo WPF.

Recursos adicionais estão disponíveis que explicam os elementos da estrutura do WPF e o roteamento de eventos com mais detalhes. Consulte as visões gerais a seguir para obter mais informações: Visão geral de comandos, Visão geral do foco, Visão geral de elementos base, Árvores no WPF e Visão geral de eventos roteados.

Confira também