Compartir a través de


Introducción a la entrada

El subsistema de Windows Presentation Foundation (WPF) proporciona una API eficaz para obtener la entrada de una variedad de dispositivos, como el mouse, el teclado, la entrada táctil y el lápiz óptico. En este tema se describen los servicios proporcionados por WPF y se explica la arquitectura de los sistemas de entrada.

API de entrada

La exposición de la API de entrada principal se encuentra en las clases de elemento base: UIElement, ContentElement, FrameworkElementy FrameworkContentElement. Para obtener más información sobre los elementos base, vea Información general sobre elementos base. Estas clases proporcionan funcionalidad para los eventos de entrada relacionados con pulsaciones de teclas, botones del mouse, rueda del mouse, movimiento del mouse, administración del foco y captura del mouse, por nombrar algunos. Al colocar la API de entrada en los elementos base, en lugar de tratar todos los eventos de entrada como servicio, la arquitectura de entrada permite que un objeto determinado de la interfaz de usuario obtenga los eventos de entrada y que admita un esquema de enrutamiento de eventos en el que más de un elemento tiene la oportunidad de controlar un evento de entrada. Muchos eventos de entrada tienen un par de eventos asociados a ellos. Por ejemplo, el evento key down está asociado con los eventos KeyDown y PreviewKeyDown. La diferencia en estos eventos radica en cómo se enrutan al elemento de destino. Los eventos de vista previa se desplazan a través del árbol de elementos desde el elemento raíz hasta el elemento de destino. Los eventos burbujeantes se propagan desde el elemento de destino hasta el elemento raíz. El enrutamiento de eventos en WPF se describe con más detalle más adelante en esta introducción y en Información general sobre eventos enrutados.

Clases de teclado y mouse

Además de la API de entrada en las clases de elemento base, las clases Keyboard y Mouse proporcionan API adicional para trabajar con la entrada de teclado y ratón.

Algunos ejemplos de la API de entrada de la Keyboard clase son la Modifiers propiedad, que devuelve la ModifierKeys tecla presionada actualmente, y el IsKeyDown método, que determina si se presiona una tecla especificada.

En el ejemplo siguiente se usa el método GetKeyStates para determinar si un Key está en estado de bajada.

// 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

Algunos ejemplos de la API de entrada de la Mouse clase son MiddleButton, que obtiene el estado del botón central del ratón, y DirectlyOver, que obtiene el elemento sobre el que el puntero del ratón está.

En el siguiente ejemplo se determina si el elemento LeftButton del mouse está en el estado Pressed.

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

Las clases Mouse y Keyboard se cubren con más detalle a lo largo de este resumen.

Entrada de lápiz táctil

WPF tiene compatibilidad integrada con .Stylus El Stylus es una entrada de lápiz popularizada por la tableta PC. Las aplicaciones WPF pueden tratar el lápiz como un mouse mediante la API del mouse, pero WPF también expone una abstracción de dispositivo de lápiz que usa un modelo similar al teclado y el mouse. Todas las API relacionadas con el lápiz óptico contienen la palabra "Stylus".

Dado que el lápiz óptico puede actuar como un mouse, las aplicaciones que admiten solo la entrada del mouse pueden obtener algún nivel de compatibilidad con lápiz óptico automáticamente. Cuando se usa el lápiz óptico de tal manera, la aplicación tiene la oportunidad de controlar el evento de lápiz óptico adecuado y, a continuación, controla el evento del mouse correspondiente. Además, los servicios avanzados, como la entrada de lápiz, también están disponibles a través de la abstracción del dispositivo de lápiz táctil. Para obtener más información sobre la entrada de lápiz, vea Introducción a la tinta.

Enrutamiento de eventos

Un FrameworkElement puede contener otros elementos como elementos secundarios en su modelo de contenido, formando un árbol de elementos. En WPF, el elemento primario puede participar en la entrada dirigida a sus elementos secundarios u otros descendientes mediante la entrega de eventos. Esto es especialmente útil para crear controles a partir de controles más pequeños, un proceso conocido como "composición de control" o "composición". Para obtener más información sobre los árboles de elementos y cómo se relacionan los árboles de elementos con las rutas de eventos, vea Árboles en WPF.

El enrutamiento de eventos es el proceso de reenvío de eventos a varios elementos, por lo que un objeto o elemento determinado a lo largo de la ruta puede optar por ofrecer una respuesta significativa (a través del control) a un evento que podría haber sido fuentedo por un elemento diferente. Los eventos enrutados usan uno de los tres mecanismos de enrutamiento: directo, burbujas y túnel. En el enrutamiento directo, el elemento de origen es el único elemento notificado y el evento no se enruta a ningún otro elemento. Sin embargo, el evento enrutado directo todavía ofrece algunas funcionalidades adicionales que solo están presentes para los eventos enrutados en lugar de los eventos CLR estándar. La burbuja trabaja de abajo hacia arriba en el árbol de elementos notificando primero al elemento que ha provocado el evento, luego al elemento primario, y así sucesivamente. La tunelización comienza en la raíz del árbol de elementos y funciona hacia abajo, finalizando con el elemento de origen original. Para obtener más información sobre los eventos enrutados, vea Información general sobre eventos enrutados.

Los eventos de entrada de WPF suelen aparecer en pares que constan de un evento de tunelización y un evento de propagación. Los eventos de tunelización se distinguen de los eventos de burbujeo con el prefijo "Preview". Por ejemplo, PreviewMouseMove es la versión de tunelado de un evento de movimiento del ratón y MouseMove es la versión de burbujeo de este evento. Este emparejamiento de eventos es una convención que se implementa en el nivel de elemento y no es una funcionalidad inherente del sistema de eventos WPF. Para obtener más información, consulte la sección Eventos de entrada de WPF en Información general sobre eventos enrutados.

Control de eventos de entrada

Para recibir la entrada en un elemento, un controlador de eventos debe estar asociado a ese evento en particular. En XAML, esto es sencillo: haces referencia al nombre del evento como un atributo del elemento que escuchará este evento. A continuación, establezca el valor del atributo en el nombre del controlador de eventos que defina, en función de un delegado. El controlador de eventos debe escribirse en código como C# y se puede incluir en un archivo de código subyacente.

Los eventos de teclado se producen cuando el sistema operativo notifica acciones clave que se producen mientras el foco del teclado está en un elemento. Los eventos de mouse y lápiz se dividen en dos categorías: eventos que notifican cambios en la posición del puntero en relación con el elemento y eventos que notifican cambios en el estado de los botones del dispositivo.

Ejemplo de evento de entrada de teclado

En el ejemplo siguiente se escucha una pulsación de tecla de flecha izquierda. Se crea un StackPanel que tiene un Button. Un controlador de eventos para detectar la pulsación de la tecla de flecha izquierda está adjunto a la instancia Button.

La primera sección del ejemplo crea el StackPanel y el Button, y adjunta el controlador de eventos para el 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

La segunda sección se escribe en código y define el controlador de eventos. Cuando se presiona la tecla de flecha izquierda y el Button tiene el foco del teclado, el controlador se ejecuta y el Background color del Button es cambiado. Si se presiona la tecla, pero no es la tecla de flecha izquierda, el color del Background cambia de nuevo a su color 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

Ejemplo de evento de entrada del mouse

En el ejemplo siguiente, se cambia el Background color de un Button objeto cuando el puntero del ratón entra en el Button. El Background color se restaura cuando el mouse sale de Button.

La primera sección del ejemplo crea el control StackPanel y el Button, y adjunta los controladores de eventos para los eventos MouseEnter y MouseLeave al 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

La segunda sección del ejemplo se escribe en código y define los controladores de eventos. Al entrar el ratón en Button, el color Background de Button se cambia a SlateGray. Cuando el ratón sale de Button, el color de Background se cambia de nuevo a Button.

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

El TextInput evento permite escuchar la entrada de texto de forma independiente del dispositivo. El teclado es el medio principal de entrada de texto, pero la voz, la escritura a mano y otros dispositivos de entrada también pueden generar entradas de texto.

Para la entrada del teclado, WPF envía primero los eventos adecuados KeyDown/KeyUp . Si esos eventos no se controlan y la clave es textual (en lugar de una clave de control, como flechas direccionales o teclas de función), se genera un TextInput evento. No siempre hay una asignación uno a uno simple entre los eventos KeyDown/KeyUp y TextInput porque varias pulsaciones de tecla pueden generar un solo carácter de texto y las pulsaciones de tecla únicas pueden generar cadenas de varios caracteres. Esto es especialmente cierto para idiomas como chino, japonés y coreano que usan editores de métodos de entrada (IME) para generar miles de caracteres posibles en sus alfabetos correspondientes.

Cuando WPF envía un KeyUp/KeyDown evento, Key se establece en Key.System si las pulsaciones de tecla podrían formar parte de un TextInput evento (si se presiona ALT+S, por ejemplo). Esto permite al código en un manejador de eventos KeyDown comprobar Key.System y, si se encuentra, delegar el procesamiento al manejador del evento TextInput que se levante posteriormente. En estos casos, se pueden usar las distintas propiedades del TextCompositionEventArgs argumento para determinar las pulsaciones de tecla originales. Del mismo modo, si un IME está activo, Key tiene el valor de Key.ImeProcessed, y ImeProcessedKey proporciona la pulsación o las pulsaciones de tecla originales.

En el ejemplo siguiente se define un controlador para el Click evento y un controlador para el KeyDown evento.

El primer segmento de código o marcado crea la interfaz de usuario.

<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

El segundo segmento de código contiene los controladores 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

Debido a que los eventos de entrada se propagan a lo largo de la ruta del evento, StackPanel recibe la entrada independientemente de qué elemento tenga el foco del teclado. El TextBox control se notifica primero y solo se llama al OnTextInputKeyDown controlador si TextBox no controla la entrada. Si se usa el PreviewKeyDown evento en lugar del KeyDown evento, primero se llama al OnTextInputKeyDown controlador.

En este ejemplo, la lógica de control se escribe dos veces: una vez para CTRL+O y otra para el evento click del botón. Esto se puede simplificar mediante comandos, en lugar de controlar los eventos de entrada directamente. Los comandos se describen en esta introducción y en Información general sobre comandos.

Tocar y manipular

El nuevo hardware y la API en el sistema operativo Windows 7 proporcionan a las aplicaciones la capacidad de recibir entradas de varios toques simultáneamente. WPF permite a las aplicaciones detectar y responder a la entrada táctil de forma similar a responder a otras entradas, como el mouse o el teclado, mediante la generación de eventos cuando se produce la entrada táctil.

WPF expone dos tipos de eventos cuando se produce la función táctil: eventos táctiles y eventos de manipulación. Los eventos táctiles proporcionan datos sin procesar sobre cada dedo en una pantalla táctil y su movimiento. Los eventos de manipulación interpretan la entrada como determinadas acciones. En esta sección se describen ambos tipos de eventos.

Prerrequisitos

Necesita los siguientes componentes para desarrollar una aplicación que responda a la función táctil.

  • Visual Studio 2010.

  • Windows 7.

  • Un dispositivo, como una pantalla táctil, que admite Windows Touch.

Terminología

Los siguientes términos se usan cuando se analiza la función táctil.

  • Touch es un tipo de entrada de usuario reconocida por Windows 7. Normalmente, la función táctil se inicia colocando los dedos en una pantalla táctil. Tenga en cuenta que los dispositivos como un panel táctil que es común en los equipos portátiles no admiten la entrada táctil si el dispositivo simplemente convierte la posición y el movimiento del dedo como entrada del mouse.

  • Multitouch es una interacción táctil que ocurre en más de un punto simultáneamente. Windows 7 y WPF admiten multitouch. Cada vez que se analiza la interacción táctil en la documentación de WPF, los conceptos se aplican a la interacción multitáctil.

  • Una manipulación se produce cuando la función táctil se interpreta como una acción física que se aplica a un objeto . En WPF, los eventos de manipulación interpretan la entrada como una traducción, expansión o manipulación de rotación.

  • touch device representa un dispositivo que produce entrada táctil, como una pantalla táctil con un solo dedo.

Controles que responden a la función táctil

Los controles siguientes se pueden desplazar arrastrando un dedo por el control si tienen contenido que se desplaza fuera de la vista.

ScrollViewer define la ScrollViewer.PanningMode propiedad adjunta que permite especificar si el movimiento panorámico táctil está habilitado horizontalmente, verticalmente, ambos o ninguno. La ScrollViewer.PanningDeceleration propiedad especifica la rapidez con la que el desplazamiento se ralentiza cuando el usuario eleva el dedo desde la pantalla táctil. La ScrollViewer.PanningRatio propiedad adjunta especifica la relación entre el desplazamiento del scroll y el desplazamiento de la manipulación.

Eventos táctiles

Las clases base, UIElement, UIElement3Dy ContentElement, definen eventos a los que puede suscribirse para que la aplicación responda a la entrada táctil. Los eventos táctiles son útiles cuando la aplicación interpreta la función táctil como algo distinto de manipular un objeto. Por ejemplo, una aplicación que permite a un usuario dibujar con uno o varios dedos se suscribiría a eventos táctiles.

Las tres clases definen los siguientes eventos, que se comportan de forma similar, independientemente de la clase de definición.

Al igual que los eventos de teclado y ratón, los eventos táctiles son eventos enrutados. Los eventos que comienzan con Preview son eventos de túnel y los eventos que comienzan con Touch son eventos de burbujeo. Para obtener más información sobre los eventos enrutados, vea Información general sobre eventos enrutados. Al controlar estos eventos, puede obtener la posición de la entrada, en relación con cualquier elemento, llamando al método GetTouchPoint o GetIntermediateTouchPoints.

Para comprender la interacción entre los eventos táctiles, considere el escenario en el que un usuario coloca un dedo en un elemento, mueve el dedo en el elemento y, a continuación, levanta el dedo del elemento. En la ilustración siguiente se muestra la ejecución de los eventos de burbujeo (se omiten los eventos de tunelización por simplicidad).

Secuencia de eventos táctiles. Eventos táctiles

En la lista siguiente se describe la secuencia de los eventos de la ilustración anterior.

  1. El TouchEnter evento se produce una vez cuando el usuario coloca un dedo en el elemento.

  2. El TouchDown evento se produce una vez.

  3. El TouchMove evento se produce varias veces a medida que el usuario mueve el dedo dentro del elemento.

  4. El evento TouchUp ocurre una sola vez cuando el usuario levanta el dedo del elemento.

  5. El TouchLeave evento se produce una vez.

Cuando se usan más de dos dedos, los eventos se producen para cada dedo.

Eventos de manipulación

En los casos en los que una aplicación permite a un usuario manipular un objeto, la UIElement clase define eventos de manipulación. A diferencia de los eventos táctiles que simplemente informan de la posición táctil, los eventos de manipulación informan de cómo se puede interpretar la entrada. Hay tres tipos de manipulaciones, traducción, expansión y rotación. En la lista siguiente se describe cómo invocar los tres tipos de manipulaciones.

  • Coloque un dedo en un objeto y mueva el dedo a través de la pantalla táctil para invocar una manipulación de traducción. Esto normalmente mueve el objeto .

  • Coloque dos dedos en un objeto y mueva los dedos más cerca o más alejados entre sí para invocar una manipulación de expansión. Normalmente cambia el tamaño del objeto.

  • Coloque dos dedos en un objeto y gire los dedos entre sí para invocar una manipulación de rotación. Normalmente, esto gira el objeto.

Puede producirse simultáneamente más de un tipo de manipulación.

Cuando hace que los objetos respondan a manipulaciones, puede hacer que el objeto parezca tener inercia. Esto puede hacer que los objetos simulan el mundo físico. Por ejemplo, cuando empujas un libro sobre una mesa, si lo empujas con suficiente fuerza, el libro seguirá moviéndose después de soltarlo. WPF permite simular este comportamiento mediante la generación de eventos de manipulación después de que los dedos del usuario liberen el objeto.

Para obtener información sobre cómo crear una aplicación que permita al usuario mover, cambiar el tamaño y girar un objeto, vea Tutorial: Creación de la aplicación First Touch.

UIElement define los siguientes eventos de manipulación.

De forma predeterminada, un UIElement no recibe estos eventos de manipulación. Para recibir eventos de manipulación en UIElement, establezca UIElement.IsManipulationEnabled en true.

Ruta de ejecución de eventos de manipulación

Considere un escenario donde un usuario "lanza" un objeto. El usuario coloca un dedo en el objeto, mueve el dedo a través de la pantalla táctil durante una corta distancia y, a continuación, levanta el dedo mientras se mueve. El resultado de esto es que el objeto se moverá bajo el dedo del usuario y continuará moviéndose después de que el usuario levante el dedo.

La ilustración siguiente muestra el recorrido de ejecución de los eventos de manipulación y proporciona información importante sobre cada uno de ellos.

Secuencia de eventos de manipulación. Eventos de manipulación

En la lista siguiente se describe la secuencia de los eventos de la ilustración anterior.

  1. El ManipulationStarting evento se produce cuando el usuario coloca un dedo en el objeto. Entre otras cosas, este evento permite establecer la ManipulationContainer propiedad . En los eventos posteriores, la posición de la manipulación será relativa a ManipulationContainer. En eventos distintos de ManipulationStarting, esta propiedad es de solo lectura, por lo que el ManipulationStarting evento es la única vez que se puede establecer esta propiedad.

  2. El ManipulationStarted evento se produce a continuación. Este evento informa del origen de la manipulación.

  3. El ManipulationDelta evento se produce varias veces a medida que los dedos de un usuario se mueven en una pantalla táctil. La DeltaManipulation propiedad de la ManipulationDeltaEventArgs clase informa de si la manipulación se interpreta como movimiento, expansión o traducción. Aquí es donde se realiza la mayor parte del trabajo de manipular un objeto.

  4. El ManipulationInertiaStarting evento se produce cuando los dedos del usuario pierden contacto con el objeto . Este evento permite especificar la desaceleración de las manipulaciones durante la inercia. Esto es para que el objeto pueda emular diferentes espacios físicos o atributos si lo desea. Por ejemplo, supongamos que la aplicación tiene dos objetos que representan elementos en el mundo físico y uno es más pesado que el otro. Puede hacer que el objeto más pesado se decelera más rápido que el objeto más ligero.

  5. El ManipulationDelta evento se produce varias veces a medida que se produce la inercia. Tenga en cuenta que este evento se produce cuando los dedos del usuario se mueven a través de la pantalla táctil y cuando WPF simula la inercia. Es decir, ManipulationDelta se produce antes y después del ManipulationInertiaStarting evento. La ManipulationDeltaEventArgs.IsInertial propiedad informa de si el evento se produce durante la ManipulationDelta inercia, por lo que puede comprobar esa propiedad y realizar diferentes acciones, dependiendo de su valor.

  6. El ManipulationCompleted evento se produce cuando finaliza la manipulación y cualquier inercia. Es decir, después de que se produzcan todos los ManipulationDelta eventos, el ManipulationCompleted evento tiene lugar para indicar que la manipulación se ha completado.

UIElement también define el ManipulationBoundaryFeedback evento . Este evento se produce cuando se llama al ReportBoundaryFeedback método en el ManipulationDelta evento . El ManipulationBoundaryFeedback evento permite a las aplicaciones o componentes proporcionar comentarios visuales cuando un objeto alcanza un límite. Por ejemplo, la Window clase controla el ManipulationBoundaryFeedback evento para hacer que la ventana se mueva ligeramente cuando se encuentra su borde.

Puede cancelar la manipulación llamando al método Cancel en los argumentos del evento en cualquier evento de manipulación excepto en el evento ManipulationBoundaryFeedback. Cuando se llama a Cancel, los eventos de manipulación ya no se generan y se producen eventos del mouse para la entrada táctil. En la tabla siguiente se describe la relación entre el momento en que se cancela la manipulación y los eventos del mouse que se producen.

El evento en el que se llama a Cancel Eventos del ratón que ocurren debido a la entrada que ya se ha producido
ManipulationStarting y ManipulationStarted Eventos de pulsación del ratón.
ManipulationDelta Eventos de pulsación del ratón y de movimiento del ratón.
ManipulationInertiaStarting y ManipulationCompleted Bajar el mouse, mover el mouse y subir eventos.

Tenga en cuenta que si llama Cancel cuando la manipulación está en inercia, el método devuelve false y la entrada no genera eventos de ratón.

Relación entre eventos táctiles y de manipulación

UIElement siempre puede recibir eventos táctiles. Cuando la propiedad IsManipulationEnabled se establece en true, un UIElement puede recibir eventos de toque y manipulación. Si el TouchDown evento no se controla (es decir, la propiedad es Handled), la false lógica de manipulación captura la entrada táctil al elemento y genera los eventos de manipulación. Si la Handled propiedad está establecida true en el TouchDown evento , la lógica de manipulación no genera eventos de manipulación. En la ilustración siguiente se muestra la relación entre los eventos táctiles y los eventos de manipulación.

Relación entre eventos táctiles y de manipulación Eventos táctiles y de manipulación

En la lista siguiente se describe la relación entre los eventos táctiles y de manipulación que se muestran en la ilustración anterior.

Enfoque

Hay dos conceptos principales que pertenecen al foco en WPF: foco de teclado y enfoque lógico.

Foco del teclado

El foco del teclado hace referencia al elemento que recibe la entrada del teclado. Solo puede haber un elemento en todo el escritorio que tenga el foco del teclado. En WPF, el elemento que tiene el foco de teclado tendrá IsKeyboardFocused establecido en true. El método estático KeyboardFocusedElement devuelve el elemento que actualmente tiene el foco del teclado.

El foco del teclado se puede obtener mediante tabulación en un elemento o haciendo clic con el ratón en determinados elementos, por ejemplo, un TextBox. El foco del teclado también se puede obtener mediante programación mediante el Focus método de la Keyboard clase . Focus intenta dar el foco del teclado al elemento especificado. El elemento devuelto por Focus es el elemento que actualmente tiene el foco del teclado.

Para que un elemento obtenga el foco del teclado, la Focusable propiedad y las IsVisible propiedades deben establecerse en true. Algunas clases, como Panel, se Focusable establecido en false de forma predeterminada; por lo tanto, es posible que tenga que establecer esta propiedad a true si desea que ese elemento pueda obtener el foco.

En el ejemplo siguiente se usa Focus para establecer el foco de teclado en un Button. El lugar recomendado para establecer el foco inicial en una aplicación está en el Loaded controlador de 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 obtener más información sobre el foco del teclado, consulte Información general sobre el foco.

Foco lógico

El foco lógico hace referencia al FocusManager.FocusedElement en un ámbito de enfoque. Puede haber varios elementos que tengan el foco lógico en una aplicación, pero solo puede haber un elemento que tenga el foco lógico en un ámbito de enfoque determinado.

Un ámbito de enfoque es un elemento contenedor que realiza un seguimiento de FocusedElement dentro de su ámbito. Cuando el foco sale de un ámbito de foco, el elemento centrado perderá el foco del teclado, pero conservará el foco lógico. Cuando el foco vuelve al área de enfoque, el elemento enfocado obtendrá el foco del teclado. Esto permite cambiar el foco del teclado entre varios ámbitos de foco, pero se asegura de que el elemento centrado dentro del ámbito de foco siga siendo el elemento centrado cuando se devuelve el foco.

Un elemento se puede convertir en un ámbito de enfoque en Lenguaje de Marcado de Aplicación Extensible (XAML) estableciendo la propiedad adjunta FocusManager a IsFocusScope en XAML, o en código, estableciendo la propiedad adjunta mediante el método true.

En el ejemplo siguiente, StackPanel se convierte en un ámbito de foco al establecer la propiedad adjunta IsFocusScope.

<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)

Las clases de WPF que son ámbitos de foco de forma predeterminada son Window, Menu, ToolBary ContextMenu.

Un elemento que tenga el foco del teclado también tendrá el foco lógico en el ámbito de enfoque al que pertenece; por lo tanto, asignar el foco a un elemento mediante el método Focus en la clase Keyboard o las clases base del elemento intentará proporcionar tanto el foco del teclado como el foco lógico al elemento.

Para determinar el elemento centrado en un ámbito de foco, use GetFocusedElement. Para cambiar el elemento centrado de un ámbito de foco, use SetFocusedElement.

Para obtener más información sobre el enfoque lógico, consulte Información general sobre el enfoque.

Posición del mouse

La API de entrada de WPF proporciona información útil con respecto a los espacios de coordenadas. Por ejemplo, la coordenada (0,0) es la coordenada superior izquierda, pero ¿cuál es el elemento superior izquierdo del árbol? ¿El elemento que es el destino de entrada? ¿El elemento donde adjuntaste el controlador de eventos? ¿O algo más? Para evitar confusiones, la API de entrada de WPF requiere que especifique el marco de referencia al trabajar con coordenadas obtenidas a través del mouse. El GetPosition método devuelve la coordenada del puntero del mouse con respecto al elemento especificado.

Captura del mouse

Los dispositivos del mouse contienen específicamente una característica modal conocida como captura del mouse. La captura del mouse se usa para mantener un estado de entrada transitorio cuando se inicia una operación de arrastrar y colocar, de modo que no se produzcan necesariamente otras operaciones que impliquen la posición nominal en pantalla del puntero del mouse. Durante el arrastre, el usuario no puede hacer clic sin anular el arrastrar y soltar, lo que hace que la mayoría de las indicaciones de desplazamiento del ratón sean inapropiadas mientras el control del ratón se mantiene en el origen del arrastre. El sistema de entrada expone las API que pueden determinar el estado de captura del mouse, así como las API que pueden forzar la captura del mouse a un elemento específico o borrar el estado de captura del mouse. Para obtener más información sobre las operaciones de arrastrar y colocar, consulte Información general sobre arrastrar y colocar.

Órdenes

Los comandos habilitan el control de entrada en un nivel más semántico que la entrada del dispositivo. Los comandos son directivas simples, como Cut, Copy, Pasteo Open. Los comandos son útiles para centralizar la lógica de comandos. Se puede acceder al mismo comando desde Menu, en ToolBar, o mediante un atajo de teclado. Los comandos también proporcionan un mecanismo para deshabilitar los controles cuando el comando deja de estar disponible.

RoutedCommand es la implementación de WPF de ICommand. Cuando se ejecuta un RoutedCommand, se generan eventos PreviewExecuted y Executed en el destino del comando, que se tunelizan y se propagan por el árbol de elementos como cualquier otra entrada. Si no se establece un destino de comando, el elemento con foco de teclado será el destino de comando. La lógica que realiza el comando se adjunta a un CommandBinding. Cuando un Executed llega a un CommandBinding para el comando específico, se invoca el ExecutedRoutedEventHandler en el CommandBinding. Este controlador realiza la acción del comando.

Para obtener más información sobre el comando, vea Información general sobre comandos.

WPF proporciona una biblioteca de comandos comunes que consta de ApplicationCommands, MediaCommands, ComponentCommands, NavigationCommandsy EditingCommands, o puede definir sus propios comandos.

En el ejemplo siguiente se muestra cómo configurar un MenuItem para que, cuando se haga clic en él, se invoque el comando Paste en el TextBox, suponiendo que el TextBox tiene el foco del 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 obtener más información sobre los comandos en WPF, vea Información general sobre comandos.

El sistema de entrada y los elementos base

Los eventos de entrada, como los eventos adjuntos definidos por las clases Mouse, Keyboard y Stylus, son generados por el sistema de entrada e inyectados en una posición particular en el modelo de objetos, basado en pruebas de colisión del árbol visual en tiempo de ejecución.

Cada uno de los eventos que Mouse, Keyboardy Stylus definen como un evento adjunto también se vuelve a exponer por las clases UIElement de elemento base y ContentElement como un nuevo evento enrutado. Las clases que controlan el evento adjunto original generan los eventos enrutados del elemento base y reutilizan los datos del evento.

Cuando el evento de entrada se asocia a un elemento de origen determinado a través de su implementación de eventos de entrada de elemento base, se puede enrutar a través del resto de una ruta de evento que se basa en una combinación de objetos de árbol lógico y visual, y se puede controlar mediante código de aplicación. Por lo general, es más conveniente controlar estos eventos de entrada relacionados con el dispositivo mediante los eventos enrutados en UIElement y ContentElement, ya que puedes usar la sintaxis del controlador de eventos más intuitiva tanto en XAML como en el código. Puede optar por controlar el evento adjunto que inició el proceso en su lugar, pero se enfrentaría a varios problemas: el evento adjunto puede estar marcado como manejado por el manejo de la clase de elemento base y debe usar métodos de acceso en lugar de sintaxis de eventos verdadera para adjuntar controladores para eventos adjuntos.

Pasos siguientes

Ahora tiene varias técnicas para gestionar la entrada en WPF. También debe tener una mejor comprensión de los distintos tipos de eventos de entrada y los mecanismos de eventos enrutados utilizados por WPF.

Hay recursos adicionales disponibles que explican los elementos del marco de WPF y el enrutamiento de eventos con más detalle. Consulte las siguientes instrucciones generales para obtener más información, Información general sobre comandos, Información general de foco, Información general de elementos base, Árboles en WPF y Información general sobre eventos enrutados.

Consulte también