Vue d'ensemble des entrées
Mise à jour : novembre 2007
Le sous-système Windows Presentation Foundation (WPF) fournit une API puissante pour obtenir des données d'entrée de divers périphériques, y compris de la souris, du clavier et du stylet.
Cette rubrique décrit les services fournis par WPF et explique l'architecture des systèmes d'entrée.
Cette rubrique comprend les sections suivantes.
- API d'entrée
- Routage d'événement
- Gestion des événements d'entrée
- Entrée de texte
- Focus
- Position de la souris
- Capture de la souris
- Commandes
- Le système d'entrée et les éléments de base
- Quoi d'autre ?
- Rubriques connexes
API d'entrée
L'exposition API d'entrée principale se trouve dans les classes d'élément de base : UIElement, ContentElement, FrameworkElement et FrameworkContentElement. Pour plus d'informations sur les éléments de base, consultez Vue d'ensemble des éléments de base. Ces classes fournissent la fonctionnalité des événements d'entrée associés aux pressions des touches, aux boutons de la souris, à la molette de la souris, aux déplacements de la souris, à la gestion du focus et à la capture de la souris, pour n'en nommer que quelques-uns. En plaçant l'API d'entrée dans les éléments de base au lieu de traiter tous les événements d'entrée comme un service, l'architecture d'entrée permet d'alimenter les événements d'entrée via un objet particulier dans l'interface utilisateur et de prendre en charge un schéma de routage d'événements qui permet à plusieurs éléments de gérer un événement d'entrée. Un grand nombre d'événements sont associés à une paire d'événements. Par exemple, l'événement de relâchement de touche est associé aux événements KeyDown et PreviewKeyDown. La différence dans ces événements réside dans leur routage vers l'élément cible. Prévisualisation du tunneling des événements dans l'arborescence, de l'élément racine à l'élément cible. Événements de propagation qui propagent de l'élément cible vers l'élément racine. Le routage d'événement dans WPF est expliqué en détail plus loin dans cette présentation générale et dans Vue d'ensemble des événements routés.
Classes de clavier et de souris
Outre l'API d'entrée dans les classes d'élément de base, les classes Keyboard et Mouse fournissent des API supplémentaires pour utiliser les entrées du clavier et de la souris.
Des exemples d'API d'entrée dans la classe Keyboard sont la propriété Modifiers qui retourne les ModifierKeys utilisées et la méthode IsKeyDown qui détermine si une touche clé spécifique est utilisée.
L'exemple suivant utilise la méthode GetKeyStates pour déterminer si l'utilisateur appuie sur une Key.
// 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;
}
Des exemples d'API d'entrées dans la classe Mouse sont le MiddleButton qui obtient l'état du bouton central de la souris et DirectlyOver qui obtient l'élément sur lequel se trouve le pointeur de la souris.
L'exemple suivant détermine si le LeftButton de la souris a l'état Pressed.
if (Mouse.LeftButton == MouseButtonState.Pressed)
{
UpdateSampleResults("Left Button Pressed");
}
Les classes Mouse et Keyboard sont couvertes en détail dans cette présentation.
Entrée du stylet
WPF a intégré le support du Stylus. Un stylet Stylus est un stylo vulgarisé par le Tablet PC. Les applications WPF peuvent gérer le stylet comme une souris en utilisant l'API de souris, mais WPF expose également une abstraction de stylet qui utilise un modèle similaire au clavier et à la souris. Toutes les API de stylet contiennent le mot "Stylus".
Étant donné que le stylet peut faire office de souris, les applications qui prennent uniquement en charge la souris peuvent toujours bénéficier d'un support de stylet automatiquement. Lorsque le stylet est utilisé de cette manière, l'application peut gérer l'événement de stylet approprié et l'événement de souris correspondant. De plus, des services de niveau supérieur, tels que l'entrée d'encre, sont également disponibles via l'abstraction du stylet. Pour plus d'informations sur l'encre comme entrée, consultez Débuter avec l'encre.
Routage d'événement
Un FrameworkElement peut contenir d'autres éléments comme éléments enfants dans son modèle de contenu pour former une arborescence d'éléments. Dans WPF, l'élément parent peut participer à l'entrée envoyée à ses éléments enfants ou d'autres descendants en gérant les événements. Cela est particulièrement utile pour générer des contrôles à partir de contrôles, un processus appelé "composition de contrôle" ou "composition". Pour plus d'informations sur les arborescences d'éléments et sur la manière dont les arborescences d'éléments sont associées aux routes d'événement, consultez Arborescences dans WPF.
Le routage d'événement est le processus d'envoi d'événements à des éléments pour qu'un objet ou un élément dans la route puisse fournir une réponse significative (via la gestion) à un événement dont la source peut correspondre à un élément différent. Les événements routés utilisent l'un de trois mécanismes de routage : routage direct, routage de propagation et tunneling. Dans le routage direct, l'élément source est le seul élément notifié, et l'événement n'est pas routé vers les autres éléments. Toutefois, l'événement routé directement offre des fonctions supplémentaires qui sont uniquement présentes pour les événements routés, par opposition aux événements CLR standard. La propagation remonte l'arborescence d'éléments en notifiant en premier l'élément qui a alimenté l'événement, puis l'élément parent, et ainsi de suite. Le tunneling démarre à la racine de l'arborescence d'éléments et la descend en s'arrêtant au niveau de l'élément source d'origine. Pour plus d'informations sur les événements routés, consultez Vue d'ensemble des événements routés.
Les événements d'entrée WPF forment généralement des paires constituées d'un événement de tunneling et d'un événement de propagation. Les événements de tunneling se distinguent des événements de propagation par le préfixe "Preview". Par exemple, PreviewMouseMove est la version de tunneling d'un événement de déplacement de la souris, et MouseMove est la version de propagation de cet événement. Cet appariement d'événement est une convention qui est implémentée au niveau de l'élément niveau et il ne correspond pas à une fonction inhérente du système d'événements WPF. Pour plus d'informations, consultez la section des événements d'entrée WPF dans Vue d'ensemble des événements routés.
Gestion des événements d'entrée
Pour recevoir l'entrée dans un élément, un gestionnaire d'événements doit être associé à l'événement. En XAML cette opération est simple ; vous faites référence au nom de l'événement sous la forme d'un attribut de l'élément qui écoutera cet événement. Ensuite, vous affectez la valeur de l'attribut au nom du gestionnaire d'événements que vous définissez, selon un délégué. Le gestionnaire d'événements doit être écrit dans le code, tel que C#, et il peut être inclus dans un fichier code-behind.
Les événements de clavier se produisent lorsque le système d'exploitation signale des actions de touche qui se produisent lorsque le focus clavier est sur un élément. Les événements de souris et de stylet entrent dans deux catégories : les événements qui signalent le changement de position du pointeur par rapport à l'élément, et les événements qui signalent le changement d'état des boutons du périphérique.
Exemple d'événement d'entrée de clavier
L'exemple suivant permet d'écouter l'utilisation de la touche de direction Gauche du clavier. Un StackPanel ayant un Button est créé. Un gestionnaire d'événements pour écouter l'utilisation de la touche de direction Gauche est attaché à l'instance Button.
La première section de l'exemple crée le StackPanel et le Button et lie le gestionnaire d'événements de 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);
La deuxième partie est écrite dans le code et elle définit le gestionnaire d'événements. Lorsque la touche de direction Gauche est utilisée et que le Button a le focus clavier, le gestionnaire s'exécute et la couleur Background du Button change. Si une touche est utilisée et qu'il ne s'agit pas de la touche de direction Gauche, la couleur de début du Background du Button est rétablie.
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;
}
}
}
Exemple d'événement d'entrée de souris
Dans l'exemple suivant, la couleur Background d'un Button change lorsque le pointeur de la souris se trouve sur le Button. La couleur Background est restaurée lorsque la souris quitte le Button.
La première section de l'exemple créé le StackPanel et le contrôle Button et lie les gestionnaires d'événements des événements MouseEnter et MouseLeave au 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);
La deuxième section de l'exemple est écrite dans le code et définit les gestionnaires d'événements. Lorsque la souris se trouve sur le bouton Button, la couleur Background du Button change SlateGray.. Lorsque la souris quitte le bouton Button, la couleur Background du Button revient à 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 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;
}
}
Entrée de texte
L'événement TextInput permet d'écouter une entrée de texte d'une manière indépendante du périphérique. Le clavier est le principal périphérique d'entrée de texte, mais la voix, l'écriture et d'autres périphériques d'entrée peuvent générer du texte également.
Pour l'entrée au clavier, WPF envoie en premier les événements KeyDown / KeyUp appropriés. Si ces événements ne sont pas gérés et qu'il s'agit de la touche d'une lettre (et non d'une touche de contrôle, telle que les touches de direction ou les touches de fonction), un événement TextInput se déclenche. Il n'existe pas toujours une association univoque simple entre des événements KeyDown/KeyUp et TextInput, car plusieurs séquences de touches peuvent générer un caractère unique et des séquences impliquant une seule touche peuvent générer des chaînes de plusieurs caractères. C'est particulièrement vrai pour le chinois, le japonais et le coréen, par exemple qui utilisent Éditeurs de méthode d'entrée (IME, Input Method Editors) pour générer des milliers de caractères dans leurs alphabets correspondants.
Lorsque WPF envoie un événement KeyUp/KeyDown, Key est affecté de la valeur Key.System si les séquences de touches peuvent faire partie d'un événement TextInput (si ALT+S est utilisé, par exemple). Ainsi, le code dans un gestionnaire d'événements KeyDown peut rechercher Key.System et, s'il le trouve, quitter le traitement du gestionnaire de l'événement déclenché TextInput qui suit. Dans ce cas, les propriétés de l'argument TextCompositionEventArgs peuvent être utilisées pour déterminer les séquences de touches d'origine. De la même, si un IME est actif, Key a la valeur Key.ImeProcessed et ImeProcessedKey donne la séquence ou les séquences de touches d'origine.
L'exemple suivant définit un gestionnaire pour l'événement Click et un gestionnaire pour l'événement KeyDown
Le premier segment du code ou de balise crée l'interface utilisateur.
<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);
Le second segment du code contient les gestionnaires d'événements
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");
}
Étant donné que les événements propagent la route d'événement, le StackPanel reçoit l'entrée quel que soit l'élément qui le focus clavier. Le contrôle TextBox est notifié en premier et le gestionnaire OnTextInputKeyDown est appelé uniquement si la TextBox n'a pas géré l'entrée. Si l'événement PreviewKeyDown est utilisé à la place de l'événement KeyDown, le gestionnaire OnTextInputKeyDown est appelé en premier.
Dans cet exemple, la logique de gestion est écrite deux fois : une fois pour CTRL+O et une fois pour l'événement Click du bouton. Cela peut être simplifié en utilisant des commandes au lieu de gérer les événements d'entrée directement. Les commandes sont expliquées dans cette présentation et dans Vue d'ensemble des commandes.
Focus
Il existe deux concepts principaux associés au focus dans WPF : le focus clavier et le focus logique.
Focus clavier
Le focus clavier fait référence à l'élément qui reçoit l'entrée au clavier. Un seul élément de l'ordinateur peut avoir le focus clavier. Dans WPF, IsKeyboardFocused, l'élément qui a le focus clavier sera affecté de true. La méthode statique KeyboardFocusedElement retourne l'élément qui a le focus clavier.
Le focus clavier peut être obtenu en accédant à un élément avec la touche Tab ou en cliquant avec le bouton de la souris sur certains éléments, tels qu'une TextBox. Le focus clavier peut également être obtenu par programme en utilisant la méthode Focus dans la classe Keyboard. Focus tente de donner à l'élément spécifié le focus clavier. L'élément retourné par Focus est l'élément qui a le focus clavier.
Pour qu'un élément obtienne le focus clavier, la propriété Focusable et les propriétés IsVisible doivent être affectées de la valeur true. Certaines classes, telles que Panel, ont false affecté par défaut à Focusable. Par conséquent, vous pouvez devoir affecter à cette propriété la valeur true pour que cet élément puisse obtenir le focus.
L'exemple suivant utilise Focus pour placer le focus clavier sur un Button. Il est recommandé de définir le focus initial dans le gestionnaire d'événements Loaded d'une application.
private void OnLoaded(object sender, RoutedEventArgs e)
{
// Sets keyboard focus on the first Button in the sample.
Keyboard.Focus(firstButton);
}
Pour plus d'informations sur le focus clavier, consultez Vue d'ensemble du focus.
Focus logique
Le focus logique fait référence à l'FocusManager.FocusedElement dans une portée de focus. Plusieurs éléments d'une application peuvent avoir le focus logique, mais un seul élément peut avoir le focus logique dans une portée de focus donnée.
Une portée de focus est un élément conteneur qui effectue le suivi de l'FocusedElement dans sa portée. Lorsque le focus quitte une portée de focus, l'élément ayant le focus perd le focus clavier, mais il conserve le focus logique. Lorsque le focus revient dans la portée de focus, l'élément ayant le focus obtient le focus clavier. Cela permet au focus clavier de changer entre des portées de focus et de s'assurer que l'élément ayant le focus dans la portée de focus continue d'avoir le focus lorsque le focus revient.
Un élément peut être converti en portée de focus en XAML (Extensible Application Markup Language) en affectant à la propriété attachée FocusManager IsFocusScope la valeur true, ou dans le code en définissant la propriété attachée à la méthode SetIsFocusScope.
L'exemple suivant convertit un StackPanel en portée de focus en définissant la propriété attachée 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);
Les classes dans WPF ayant des portées de focus par défaut sont Window, Menu, ToolBar et ContextMenu.
Un élément qui a le focus clavier a également le focus logique pour la portée de focus à laquelle il appartient. Par conséquent, la définition du focus dans un élément avec la méthode Focus dans la classe Keyboard ou les classes d'élément de base tente de donner à l'élément le focus clavier et le focus logique.
Pour déterminer l'élément ayant le focus dans une portée de focus, utilisez GetFocusedElement. Pour modifier l'élément ayant le focus d'une portée de focus, utilisez SetFocusedElement.
Pour plus d'informations sur le focus logique, consultez Vue d'ensemble du focus.
Position de la souris
L'entrée de l'API WPF fournit des informations utiles sur les espaces de coordonnée. Par exemple, la coordonnée (0,0) est la coordonnée supérieure gauche, mais de quel élément de l'arborescence ? L'élément qui correspond à la cible d'entrée ? L'élément que vous avez attaché au gestionnaire d'événements ? Ou autre chose ? Pour éviter toute confusion, l'entrée de l'API WPF implique que vous spécifiez votre système de référence lorsque vous travaillez avec les coordonnées obtenues à travers la souris. La méthode GetPosition retourne la coordonnée du pointeur de la souris par rapport à l'élément spécifié.
Capture de la souris
Les souris maintiennent spécifiquement une caractéristique modale appelée capture de la souris. La capture de la souris est utilisée pour maintenir un état d'entrée transitionnel lorsqu'une opération Glisser-déplacer démarre afin que les autres opérations qui impliquent la position affichée nominale du pointeur de la souris ne soient pas nécessairement exécutées. Lorsque la souris glisse, l'utilisateur ne peut pas cliquer sans abandonner la fonction Glisser-déplacer, ce qui rend les informations de pointage de la souris inappropriées lorsque la capture de la souris est détenue par l'origine du glissement. Le système d'entrée expose les API qui peuvent déterminer l'état de capture de la souris, ainsi que les API qui peuvent forcer la capture de la souris dans un élément spécifique, ou effacer l'état de capture de la souris. Pour plus d'informations sur les opérations Glisser-déplacer, consultez Vue d'ensemble du glisser-déplacer.
Commandes
Les commandes permettent de gérer l'entrée à un niveau plus sémantique que l'entrée de périphérique. Les commandes sont des directives simples, telles que Cut, Copy, Paste ou Open. Les commandes sont utiles pour centraliser la logique de commande. La même commande peut être accessible depuis un Menu, dans une ToolBar, ou via un raccourci clavier. Les commandes fournissent également un mécanisme permettant de désactiver des contrôles lorsque la commande devient indisponible.
RoutedCommand est l'implémentation WPF de ICommand. Lorsqu'un RoutedCommand est exécuté, un événement PreviewExecuted et un événement Executed sont déclenchés sur la cible de commande qui utilisent le tunneling et la propagation dans l'arborescence d'éléments comme tout autre entrée. Si aucune cible de commande n'est définie, l'élément avec le focus clavier devient la cible de la commande. La logique qui exécute la commande est attachée à une CommandBinding. Lorsqu'un événement Executed atteint une CommandBinding pour une commande spécifique, le ExecutedRoutedEventHandler dans la CommandBinding est appelé. Ce gestionnaire exécute l'action de la commande.
Pour plus d'informations sur l'exécution des commandes, consultez Vue d'ensemble des commandes.
WPF fournit une bibliothèque de commandes communes constituée des ApplicationCommands, MediaCommands, ComponentCommands, NavigationCommands et EditingCommands, mais vous pouvez définir votre propre bibliothèque.
L'exemple suivant indique comment définir un MenuItem pour que, lorsque l'utilisateur clique dessus, il appelle la commande Paste dans la TextBox, si la TextBox a le focus clavier.
<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;
Pour plus d'informations sur les commandes dans WPF, consultez Vue d'ensemble des commandes..
Le système d'entrée et les éléments de base
Les événements d'entrée, tels que les événements attachés définis par les classes Mouse, Keyboard et Stylus sont déclenchés par le système d'entrée et injectés dans une position particulière dans le modèle objet selon le test d'atteinte de l'arborescence visuelle au moment de l'exécution.
Chacun des événements que Mouse, Keyboard et Stylus définissent comme événement attaché est également ré-exposé par les classes d'élément de base UIElement et ContentElement sous la forme d'un nouvel événement routé. Les événements routés par les éléments de base sont générés par les classes qui gèrent l'événement attaché d'origine et qui réutilisent les données d'événement.
Lorsque l'événement d'entrée est associé à un élément source particulier à travers son implémentation d'événement d'entrée d'élément de base, il peut être routé à travers le reste d'un itinéraire d'événement basé sur une combinaison d'objets d'arborescences logique et visuelle et il peut être géré par le code d'application. En général, il est préférable de gérer ces événements d'entrée de périphérique à l'aide des événements routés dans UIElement et ContentElement, car vous pouvez utiliser une syntaxe de gestionnaire d'événements plus intuitive en XAML et dans le code. Vous pouvez décider de gérer l'événement attaché qui a initialisé à la place le processus, mais dans ce cas plusieurs problèmes apparaissent : l'événement attaché peut être marqué comme étant géré par la gestion de classe des éléments de base, et vous devez utiliser des méthodes d'accesseur plutôt qu'une vraie syntaxe d'événement pour joindre des gestionnaires pour les événements attachés.
Quoi d'autre ?
Vous connaissez maintenant plusieurs techniques de gestion des entrées dans WPF. Maintenant, vous devez aussi mieux comprendre les divers types d'événements d'entrée et les mécanismes des événements routés utilisés par WPF.
Des ressources supplémentaires, qui expliquent plus en détail les éléments d'infrastructure WPF et le routage des événements, sont disponibles. Pour plus d'informations à ce sujet, consultez les vues d'ensemble suivantes : Vue d'ensemble des commandes, Vue d'ensemble du focus, Vue d'ensemble des éléments de base, Arborescences dans WPF, et Vue d'ensemble des événements routés.
Voir aussi
Concepts
Vue d'ensemble des événements routés
Vue d'ensemble des éléments de base