Примечание
Для доступа к этой странице требуется авторизация. Вы можете попробовать войти или изменить каталоги.
Для доступа к этой странице требуется авторизация. Вы можете попробовать изменить каталоги.
Подсистема Windows Presentation Foundation (WPF) предоставляет мощный API для получения входных данных от различных устройств, включая мышь, клавиатуру, сенсорный ввод и перо. В этом разделе описываются службы, предоставляемые WPF, и объясняется архитектура входных систем.
API ввода
Основное воздействие API входных данных обнаруживается в базовых классах элементов: UIElement, , ContentElementFrameworkElementи FrameworkContentElement. Дополнительные сведения о базовых элементах см. в разделе "Общие сведения о базовых элементах". Эти классы предоставляют функциональные возможности для событий ввода, связанных с нажатиями клавиш, кнопками мыши, колесикой мыши, перемещением мыши, управлением фокусом и записью мыши, чтобы назвать несколько. Поместив входной API на базовые элементы, а не обрабатывая все входные события в качестве службы, входная архитектура позволяет входным событиям быть источником определенного объекта в пользовательском интерфейсе и поддерживать схему маршрутизации событий, в которой несколько элементов имеют возможность обрабатывать входное событие. Многие входные события связаны с ними парой событий. Например, событие нажатия клавиши связывается с событиями KeyDown и PreviewKeyDown. Разница между этими событиями заключается в том, как они направляются к целевому элементу. Предварительные события проходят по дереву элементов, начиная с корневого и заканчивая целевым элементом. События, распространяющиеся путём всплытия, проходят от целевого элемента к корневому элементу. Маршрутизация событий в WPF подробно рассматривается далее в этом обзоре и в обзоре перенаправленных событий.
Классы клавиатуры и мыши
Помимо API ввода в базовых классах элементов, Keyboard класс и Mouse классы предоставляют дополнительный API для работы с клавиатурой и вводом мыши.
Примеры входного API класса Keyboard — Modifiers это свойство, которое возвращает ModifierKeys нажатый в данный момент, и IsKeyDown метод, который определяет, нажимается ли указанный ключ.
В следующем примере используется метод GetKeyStates для определения того, находится ли 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;
}
' 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
Примерами входного API класса Mouse являются MiddleButton, которое получает состояние средней кнопки мыши, и DirectlyOver, которое получает элемент, над которым находится указатель мыши.
В следующем примере определяется, находится ли LeftButton на мыши в Pressed состоянии.
if (Mouse.LeftButton == MouseButtonState.Pressed)
{
UpdateSampleResults("Left Button Pressed");
}
If Mouse.LeftButton = MouseButtonState.Pressed Then
UpdateSampleResults("Left Button Pressed")
End If
В этом обзоре подробно рассматриваются классы Mouse и Keyboard.
Входные данные стилуса
WPF поддерживает встроенную Stylusподдержку. Этот Stylus – это ввод пера, ставший популярным благодаря Tablet PC. Приложения WPF могут рассматривать перо как мышь с помощью API мыши, но WPF также предоставляет абстракцию устройства пера, которая использует модель, аналогичную клавиатуре и мыши. Все API- интерфейсы, связанные со стилусом, содержат слово "Stylus".
Так как перо может выступать в качестве мыши, приложения, поддерживающие только входные данные мыши, по-прежнему могут автоматически получать некоторый уровень поддержки пера. Когда перо используется таким образом, приложение получает возможность обрабатывать соответствующее событие пера, а затем обрабатывает соответствующее событие мыши. Кроме того, службы более высокого уровня, такие как ввод рукописного ввода, также доступны через абстракции устройства пера. Дополнительные сведения о рукописном вводе см. в статье "Начало работы с рукописным вводом".
Маршрутизация событий
FrameworkElement может содержать другие элементы, которые выступают в качестве дочерних элементов в его модели содержимого, формируя дерево элементов. В WPF родительский элемент может участвовать в входных данных, направленных на его дочерние элементы или другие потомки, передав события. Это особенно полезно для создания элементов управления из небольших элементов управления, процесса, известного как "композиция элементов управления" или "состав". Дополнительные сведения о деревьях элементов и о том, как деревья элементов связаны с маршрутами событий, см. в разделе "Деревья" в WPF.
Маршрутизация событий — это процесс переадресации событий в несколько элементов, чтобы конкретный объект или элемент вдоль маршрута мог предложить значительный ответ (через обработку) событию, которое, возможно, было вызвано другим элементом. Перенаправленные события используют один из трех механизмов маршрутизации: прямой, всплытие и просачивание. При прямой маршрутизации уведомляется только исходный элемент, и событие не передается другим элементам. Однако прямое маршрутизированное событие по-прежнему предоставляет некоторые дополнительные возможности, которые присутствуют только для маршрутизированных событий в отличие от стандартных событий CLR. Bubbling работает вверх по дереву элементов, сначала уведомляя элемент, который инициировал событие, а затем родительский элемент и т. д. Туннелирование начинается в корне дерева элементов и передвигается вниз, заканчивая исходным элементом. Дополнительные сведения о перенаправленных событиях см. в разделе Общие сведения о перенаправленных событиях.
События ввода WPF обычно представляют собой пары, состоящие из туннелируемого события и всплывающего события. События туннелирования отличаются от бурых событий с префиксом "Предварительная версия". Например, PreviewMouseMove является версией события перемещения мыши в режиме туннелирования, а MouseMove — в режиме всплытия. Эта связь событий — это соглашение, реализованное на уровне элемента и не является неотъемлемой возможностью системы событий WPF. Дополнительные сведения см. в разделе "Входные события WPF" в Обзор маршрутизируемых событий.
Обработка событий ввода
Чтобы получить входные данные в элементе, обработчик событий должен быть связан с этим конкретным событием. В XAML это просто: вы ссылаетесь на имя события в качестве атрибута элемента, который будет прослушивать это событие. Затем установите значение атрибута в имя обработчика событий, который вы определяете, основываясь на делегате. Обработчик событий должен быть написан в коде, например C# и может быть включен в файл программной части.
События клавиатуры происходят, когда операционная система сообщает о ключевых действиях, происходящих при фокусе клавиатуры на элементе. События мыши и стилуса делятся на две категории: события, сообщающие об изменениях положения указателя относительно элемента, и события, сообщающие об изменениях состояния кнопок устройства.
Пример события ввода клавиатуры
Следующий пример отслеживает нажатие клавиши со стрелкой влево. Создается StackPanel, который имеет Button. Обработчик событий, который реагирует на нажатие клавиши со стрелкой влево, подключен к экземпляру Button.
Первый раздел примера создает StackPanel и Button, а также присоединяет обработчик событий для 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
Второй раздел написан в коде и определяет обработчик событий. Когда нажимается клавиша стрелки влево и Button находится в фокусе клавиатуры, запускается обработчик, и цвет Button изменяется на Background. Если клавиша нажата, но это не клавиша со стрелкой влево, Background цвет Button изменяется обратно на начальный цвет.
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
Пример события ввода мыши
В следующем примере цвет объекта BackgroundButton изменяется, когда указатель мыши входит в область Button. Цвет Background восстанавливается, когда мышь покидает Button.
Первый раздел примера создает элементы управления StackPanel и Button и присоединяет обработчики событий для событий MouseEnter и MouseLeave к 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
Второй раздел примера написан в коде и определяет обработчики событий. При наведении мыши на Button изменяется цвет Background элемента Button на SlateGray. Когда мышь покидает Button, цвет Button изменяется обратно на 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
Ввод текста
Это TextInput событие позволяет прослушивать ввод текста независимо от устройства. Клавиатура является основным средством ввода текста, но речь, рукописный ввод и другие устройства ввода также могут создавать текстовые входные данные.
Для ввода клавиатуры WPF сначала отправляет соответствующие KeyDown/KeyUp события. Если эти события не обрабатываются, и ключ является текстовым (а не ключом управления, например стрелками направления или ключами функции), вызывается TextInput событие. Между событиями KeyDown/KeyUp и TextInput не всегда существует простое сопоставление один к одному, так как несколько нажатий клавиш могут создавать один символ текста, а единичные нажатия клавиш могут генерировать строки из нескольких символов. Это особенно верно для таких языков, как китайский, японский и корейский, которые используют редакторы методов ввода (IMEs) для создания тысяч возможных символов в их соответствующих алфавитах.
Когда WPF отправляет KeyUp/KeyDown событие, Key устанавливается в Key.System, если нажатия клавиш могут стать частью TextInput события (например, если нажата клавиша ALT+S). Это позволяет коду KeyDown в обработчике событий проверять наличие Key.System, и, если найдено, передать обработку для обработчика следующего события TextInput. В этих случаях для определения исходных нажатий клавиш можно использовать различные свойства TextCompositionEventArgs аргумента. Аналогичным образом, если IME активен, Key имеет значение Key.ImeProcessedи ImeProcessedKey дает исходные нажатия клавиш или нажатия клавиш.
В следующем примере определяется обработчик события Click и обработчик события KeyDown .
Первый сегмент кода или разметки создает пользовательский интерфейс.
<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
Второй сегмент кода содержит обработчики событий.
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
Поскольку входные события пузырьком распространяются по цепочке событий, StackPanel получает входные данные неважно от того, какой элемент имеет фокус клавиатуры. Элемент TextBox управления сначала уведомляется, а OnTextInputKeyDown
обработчик вызывается только в том случае, если TextBox не обработал входные данные. Если используется событие PreviewKeyDown вместо события KeyDown, обработчик OnTextInputKeyDown
вызывается первым.
В этом примере логика обработки записывается два раза— один раз для CTRL+O и снова для события нажатия кнопки. Это можно упростить с помощью команд, а не обработки входных событий напрямую. Команды рассматриваются в этом обзоре и в обзоре команд.
Касание и манипуляция
Новое оборудование и API в операционной системе Windows 7 предоставляет приложениям возможность одновременно получать входные данные от нескольких касаний. WPF позволяет приложениям обнаруживать и реагировать на касание таким образом, как реагирование на другие входные данные, например мышь или клавиатура, вызывая события при касании.
WPF предоставляет два типа событий при касании: события касания и события манипуляции. События касания предоставляют необработанные данные о каждом пальце на сенсорном экране и его движении. События манипуляции интерпретируют входные данные как определенные действия. Оба типа событий рассматриваются в этом разделе.
Предпосылки
Для разработки приложения, реагирующего на касание, вам потребуется следующие компоненты.
Visual Studio 2010.
Windows 7.
Устройство, например сенсорный экран, поддерживающий Windows Touch.
Терминология
При обсуждении касания используются следующие термины.
Сенсорный ввод — это тип пользовательского ввода, распознаваемого Windows 7. Как правило, сенсорный ввод инициируется путем размещения пальцев на сенсорном экране. Обратите внимание, что устройства, такие как сенсорные панели, распространенные на ноутбуках, не поддерживают сенсорный ввод, если они просто преобразуют положение и движение пальца в ввод мыши.
Multitouch — это касание, которое происходит с нескольких точек одновременно. Windows 7 и WPF поддерживают мультитач. Каждый раз, когда касание упоминается в документации по WPF, эти понятия применяются к мультитач.
Манипуляция возникает, когда касание интерпретируется как физическое действие, которое применяется к объекту. В WPF события манипуляции интерпретируют входные данные как преобразование, расширение или манипуляцию поворотом.
Представляет
touch device
устройство, которое создает сенсорный ввод, например один палец на сенсорном экране.
Элементы управления, реагирующие на касание
Следующие элементы управления можно прокрутить, перетаскивая пальцем по элементу управления, если он содержит содержимое, прокручиваемое вне представления.
Элемент ScrollViewer определяет присоединенное ScrollViewer.PanningMode свойство, позволяющее указать, включена ли сенсорная прокрутка по горизонтали, по вертикали, обоих или ни один. Свойство ScrollViewer.PanningDeceleration указывает, как быстро прокрутка замедляется, когда пользователь поднимает палец с сенсорного экрана. Присоединенное ScrollViewer.PanningRatio свойство указывает соотношение смещения прокрутки к смещению перемещения.
События касания
Базовые классы, UIElementUIElement3Dа ContentElementтакже определяют события, на которые можно подписаться, чтобы приложение ответило на касание. События касания полезны, если приложение интерпретирует касание как что-то другое, кроме обработки объекта. Например, приложение, позволяющее пользователю рисовать с одним или несколькими пальцами, подписывается на события касания.
Все три класса определяют следующие события, которые ведут себя аналогично независимо от определяющего класса.
Как и события клавиатуры и мыши, события касания являются маршрутизируемыми событиями. События, начинающиеся с Preview
, являются событиями туннелирования, а события, начинающиеся с Touch
, являются событиями всплытия. Дополнительные сведения о перенаправленных событиях см. в разделе Общие сведения о перенаправленных событиях. При обработке этих событий можно получить положение входных данных относительно любого элемента, вызвав GetTouchPoint метод или GetIntermediateTouchPoints метод.
Чтобы понять взаимодействие между событиями касания, рассмотрим сценарий, в котором пользователь помещает один палец на элемент, перемещает палец в элемент, а затем поднимает палец из элемента. На следующем рисунке показано выполнение всплывающих событий (события туннелирования опущены для простоты).
События касания
В следующем списке описывается последовательность событий на предыдущем рисунке.
Событие TouchEnter происходит один раз, когда пользователь помещает пальцем на элемент.
Событие TouchDown происходит один раз.
Событие TouchMove происходит несколько раз, когда пользователь перемещает палец внутри элемента.
Событие TouchUp происходит один раз, когда пользователь поднимает палец из элемента.
Событие TouchLeave происходит один раз.
При использовании более двух пальцев события происходят для каждого пальца.
События манипуляции
В случаях, когда приложение позволяет пользователю управлять объектом, UIElement класс определяет события манипуляции. В отличие от событий касания, которые просто сообщают о положении касания, события манипуляции сообщают о том, как можно интерпретировать входные данные. Существует три типа манипуляций, перевода, расширения и поворота. В следующем списке описывается, как вызвать три типа манипуляций.
Коснитесь объекта пальцем и переместите его по сенсорному экрану, чтобы вызвать манипуляцию перевода. Обычно это перемещает объект.
Поместите два пальца на объект и переместите пальцы ближе друг к другу или дальше друг от друга, чтобы вызвать манипуляцию расширения. Обычно это изменение размера объекта.
Поместите два пальца на объект и поверните пальцы вокруг друг друга, чтобы вызвать манипуляцию поворотом. Обычно это поворачивает объект.
Несколько типов манипуляций могут выполняться одновременно.
При воздействии на объекты так, чтобы они реагировали на манипуляции, можно создать впечатление, что объект обладет инерцией. Это может заставить ваши объекты симулировать физический мир. Например, при толкании книги по столу, если вы толкаете достаточно сильно, книга будет продолжать двигаться после того, как вы её отпустите. WPF позволяет имитировать это поведение, вызывая события манипуляции после того, как пальцы пользователя освобождают объект.
Сведения о том, как создать приложение, которое позволяет пользователю перемещать, изменять размер и повернуть объект, см. в пошаговом руководстве по созданию первого сенсорного приложения.
Определяет UIElement следующие события манипуляции.
По умолчанию UIElement не получает эти события манипуляции. Чтобы получать события манипуляции на UIElement, установите UIElement.IsManipulationEnabled в true
.
Путь выполнения событий манипуляции
Рассмотрим сценарий, в котором пользователь "бросает" объект. Пользователь помещает палец на объект, перемещает палец через сенсорный экран на короткое расстояние, а затем поднимает палец во время перемещения. Результатом этого является то, что объект будет перемещаться под пальцем пользователя и продолжать двигаться после того, как пользователь поднимает палец.
На следующем рисунке показан путь выполнения событий манипуляции и важные сведения о каждом событии.
События манипуляции
В следующем списке описывается последовательность событий на предыдущем рисунке.
Событие ManipulationStarting возникает, когда пользователь помещает палец на объект. Помимо прочего, это событие позволяет задать ManipulationContainer свойство. В последующих событиях позиция манипуляции будет относительна по отношению к ManipulationContainer. В событиях, кроме ManipulationStarting, это свойство доступно только для чтения, поэтому событие ManipulationStarting является единственным временем, когда можно установить это свойство.
Следующее событие ManipulationStarted происходит. Это событие сообщает о происхождении манипуляции.
Событие ManipulationDelta происходит несколько раз, когда пальцы пользователя перемещаются на сенсорном экране. Свойство DeltaManipulationManipulationDeltaEventArgs класса сообщает, интерпретируется ли манипуляция как перемещение, расширение или перевод. Именно здесь выполняется большая часть работы по обработке объекта.
Событие ManipulationInertiaStarting возникает, когда пальцы пользователя теряют контакт с объектом. Это событие позволяет указать замедление манипуляций во время инерции. Это позволяет объекту эмулировать различные физические пространства или атрибуты при выборе. Например, предположим, что приложение имеет два объекта, представляющих элементы в физическом мире, и один из них тяжелее, чем другой. Вы можете замедлить более тяжелый объект быстрее, чем более легкий объект.
Событие ManipulationDelta происходит несколько раз во время инерции. Обратите внимание, что это событие возникает, когда пальцы пользователя перемещаются по сенсорному экрану и когда WPF имитирует инерцию. Другими словами, ManipulationDelta происходит до и после ManipulationInertiaStarting события. Свойство ManipulationDeltaEventArgs.IsInertial сообщает, происходит ли ManipulationDelta событие во время инерции, чтобы проверить это свойство и выполнить различные действия в зависимости от его значения.
Событие ManipulationCompleted происходит, когда манипуляция и любая инерция заканчивается. То есть после того, как происходят все ManipulationDelta события, ManipulationCompleted событие возникает, чтобы сигнализировать о завершении манипуляции.
UIElement также определяет событие ManipulationBoundaryFeedback. Это событие происходит, когда метод ReportBoundaryFeedback вызывается в событии ManipulationDelta. Событие ManipulationBoundaryFeedback позволяет приложениям или компонентам предоставлять визуальные отзывы при попадании объекта на границу. Например, класс обрабатывает ManipulationBoundaryFeedback событие, Window чтобы окно слегка перемещалось при обнаружении края.
Можно отменить манипуляцию, вызвав метод Cancel для аргументов события в любом событии манипуляции, кроме события ManipulationBoundaryFeedback. При вызове Cancel события манипуляции больше не вызываются, и для касания срабатывают события мыши. В следующей таблице описывается связь между временем отмены манипуляции и событиями мыши, которые происходят.
Событие, в которое вызывается отмена | События мыши, которые происходят для входных данных, которые уже произошли |
---|---|
ManipulationStarting и ManipulationStarted. | Наведите указатель мыши на события. |
ManipulationDelta | События перемещения мыши вниз и мыши. |
ManipulationInertiaStarting и ManipulationCompleted. | События нажатия, перемещения и отпускания мыши. |
Обратите внимание, что при вызове Cancel , когда манипуляция находится в инерции, метод возвращает false
и входные данные не вызывают события мыши.
Связь между событиями касания и манипуляции
Элемент UIElement всегда может получать события касания.
IsManipulationEnabled Когда для свойства задано true
, UIElement может получать как события касания, так и манипуляции.
TouchDown Если событие не обрабатывается (то есть свойство Handledfalse
), логика манипуляции фиксирует касание к элементу и создает события манипуляции. Если в событии TouchDown свойство Handled задано true
, логика манипуляции не создает события манипуляции. На следующем рисунке показана связь между событиями касания и событиями манипуляции.
События касания и манипуляции
В следующем списке описывается связь между событиями касания и манипуляции, отображаемыми на предыдущем рисунке.
Когда первое сенсорное устройство создает TouchDown событие на UIElementобъекте, логика манипуляции вызывает CaptureTouch метод, который создает GotTouchCapture событие.
При возникновении GotTouchCapture логика манипуляции вызывает метод Manipulation.AddManipulator, который генерирует событие ManipulationStarting.
Когда происходят TouchMove события, логика манипуляции создает события ManipulationDelta, которые возникают перед событием ManipulationInertiaStarting.
Когда последнее сенсорное устройство на элементе вызывает TouchUp событие, логика манипуляции создает ManipulationInertiaStarting событие.
Фокус
Существует два основных понятия, относящиеся к фокусу в WPF: фокус клавиатуры и логический фокус.
Фокус клавиатуры
Фокус клавиатуры относится к элементу, получающему ввод с клавиатуры. На рабочем столе может быть только один элемент с фокусом клавиатуры. В WPF элемент, имеющий фокус клавиатуры, будет изменен с IsKeyboardFocused на true
.
Keyboard Статический метод FocusedElement возвращает элемент, который в настоящее время имеет фокус клавиатуры.
Фокус клавиатуры можно получить, переместившись к элементу с помощью клавиши Tab или щелкая мышью по определённым элементам, например TextBox. Фокус клавиатуры также можно получить программным способом с помощью метода Focus в классе Keyboard. Focus пытается дать клавиатурный фокус указанному элементу. Элемент, возвращаемый Focus, это элемент, который в данный момент имеет фокус клавиатуры.
Чтобы элемент получил фокус клавиатуры, свойство Focusable и свойства IsVisible должны иметь значение true. Некоторые классы, такие как Panel, имеют Focusable установленное на false
по умолчанию; поэтому, если требуется, чтобы этот элемент мог получить фокус, может потребоваться установить значение этого свойства на true
.
В следующем примере используется Focus, чтобы установить фокус клавиатуры на Button. Рекомендуемое место для задания начального фокуса в приложении находится в обработчике Loaded событий.
private void OnLoaded(object sender, RoutedEventArgs e)
{
// Sets keyboard focus on the first Button in the sample.
Keyboard.Focus(firstButton);
}
Private Sub OnLoaded(ByVal sender As Object, ByVal e As RoutedEventArgs)
' Sets keyboard focus on the first Button in the sample.
Keyboard.Focus(firstButton)
End Sub
Дополнительные сведения о фокусе клавиатуры см. в разделе "Обзор фокуса".
Логический фокус
Логический фокус означает FocusManager.FocusedElement в области фокуса. В приложении может быть несколько элементов с логическим фокусом, но в определенной области фокуса может быть только один элемент с логическим фокусом.
Элемент фокусировки — это контейнер, который отслеживает FocusedElement в пределах своей области. Когда элемент фокуса выходит за пределы области фокусировки, он потеряет фокус клавиатуры, но сохранит логический фокус. При возвращении в область фокуса, элемент получит фокусировку клавиатурой. Это позволяет изменять фокус клавиатуры между несколькими областями, но гарантирует, что выделенный элемент внутри области фокуса останется выделенным элементом при возврате фокуса.
Элемент можно превратить в область фокуса в языке разметки расширяемых приложений (XAML), задав присоединенное свойство FocusManagerIsFocusScope равным true
, или в коде, установив присоединенное свойство с использованием метода SetIsFocusScope.
В следующем примере StackPanel превращается в область фокуса за счёт установки присоединенного свойства 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)
Классы в WPF, которые являются областями фокуса по умолчанию, являются Window, Menu, ToolBarи ContextMenu.
Элемент, имеющий фокус клавиатуры, также будет иметь логический фокус в контексте области фокуса, к которой он принадлежит. Таким образом, установка фокуса на элемент с использованием метода Focus класса Keyboard или базовых классов элементов попытается предоставить элементу фокус клавиатуры и логический фокус.
Чтобы определить элемент фокуса в области фокуса, используйте GetFocusedElement. Чтобы изменить элемент фокуса для области видимости, используйте SetFocusedElement.
Дополнительные сведения о логическом фокусе см. в разделе "Обзор фокуса".
Положение мыши
API входных данных WPF предоставляет полезные сведения о координатных пространствах. Например, координата — это верхняя левая координата (0,0)
, но верхняя левая часть какого элемента в дереве? Элемент, который является целевым объектом ввода? Элемент, к которому подключен обработчик событий? Или что-то другое? Чтобы избежать путаницы, API входных данных WPF требует, чтобы вы указывали свою систему отсчета при работе с координатами, полученными с помощью мыши. Метод GetPosition возвращает координату указателя мыши относительно указанного элемента.
Захват мыши
Устройства мыши специально содержат модальную характеристику, известную как захват мыши. Захват мыши используется для поддержания переходного состояния ввода при запуске операции перетаскивания, чтобы другие операции, связанные с номинальной позицией указателя мыши, не происходили автоматически. Во время перетаскивания пользователь не может щелкнуть без прерывания перетаскивания, что делает большинство подсказок мыши неуместным, пока захват мыши удерживается источником перетаскивания. Входная система предоставляет API-интерфейсы, которые могут определять состояние захвата мыши, а также API-интерфейсы, которые могут принудительно захватывать мышь для определенного элемента или очищать состояние захвата мыши. Дополнительные сведения об операциях перетаскивания см. в разделе "Обзор перетаскивания".
Команды
Команды позволяют обрабатывать входные данные на более семантическом уровне, чем входные данные устройства. Команды — это простые директивы, такие как Cut
, Paste
Copy
или Open
. Команды полезны для централизации логики команд. К той же команде можно получить доступ с помощью Menu, на ToolBar, или через сочетание клавиш. Команды также предоставляют механизм отключения элементов управления, когда команда становится недоступной.
RoutedCommand — реализация WPF ICommand. Когда RoutedCommand выполняется, на целевом объекте команды инициируются события PreviewExecuted и Executed, которые проходят через дерево элементов, распространяясь подобно другим входным данным. Если целевой объект команды не задан, элемент с фокусом клавиатуры будет целевым объектом команды. Логика, выполняющая команду, присоединена к объекту CommandBinding. Когда событие достигает CommandBinding для этой конкретной команды Executed, вызывается ExecutedRoutedEventHandler на CommandBinding. Этот обработчик выполняет действие команды.
Дополнительные сведения о команде см. в разделе "Обзор команд".
WPF предоставляет библиотеку общих команд, состоящую из ApplicationCommands, MediaCommands, ComponentCommands, NavigationCommands и EditingCommands, или вы можете определить собственные.
В следующем примере показано, как настроить MenuItem, чтобы при щелчке она вызвала команду Paste на TextBox, при условии, что TextBox имеет фокус клавиатуры.
<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
Дополнительные сведения о командах в WPF см. в разделе "Обзор команд".
Входная система и базовые элементы
Входные события, такие как присоединенные события, определенные классами Mouse, Keyboard и Stylus, создаются входной системой и внедряются в определенную позицию в объектной модели на основе тестирования визуального дерева при выполнении программы.
Каждое из событий, которые Mouse, Keyboard и Stylus определяют как присоединенное событие, также повторно предоставляется классами UIElement и ContentElement базовых элементов в качестве нового маршрутизированного события. Маршрутизуемые события базового элемента создаются классами, которые обрабатывают исходное присоединенное событие и повторно используют данные этого события.
Когда событие ввода будет связано с определенным исходным элементом через реализацию события ввода базового элемента, его можно направлять через оставшуюся часть маршрута событий, основанного на сочетании логических и визуальных объектов дерева, и обрабатываться кодом приложения. Как правило, удобнее обрабатывать эти события ввода, связанные с устройством, используя маршрутизируемые события на UIElement и ContentElement, поскольку можно использовать более интуитивно понятный синтаксис обработчика событий как в XAML, так и в коде. Вместо этого вы можете обработать присоединенное событие, инициирующее процесс, но вам придется столкнуться с несколькими проблемами: присоединенное событие может быть помечено обработкой базового класса элементов, и вам нужно использовать методы доступа, а не истинный синтаксис событий, чтобы подключить обработчики для присоединенных событий.
Дальнейшие действия
Теперь у вас есть несколько методов обработки входных данных в WPF. Кроме того, необходимо улучшить представление о различных типах входных событий и механизмах перенаправленных событий, используемых WPF.
Дополнительные ресурсы доступны, объясняющие элементы платформы WPF и маршрутизацию событий более подробно. Дополнительные сведения см. в следующих обзорах: Обзор команд, Обзор фокуса, Обзор базовых элементов, Деревья в WPF, и Обзор перенаправляемых событий.
См. также
- Обзор основных аспектов
- Обзор команд
- Обзор маршрутизированных событий
- Обзор базовых элементов
- Свойства
.NET Desktop feedback