События ввода с использованием мыши

60

События мыши выполняют несколько связанных задач. Самые главные события мыши позволяют реагировать на перемещение указателя мыши над элементами. Это события MouseEnter (возникает, когда указатель мыши появляется над элементом) и MouseLeave (происходит, когда указатель мыши покидает элемент). Оба они являются прямыми событиями (direct events), то есть не используют туннелирования или пузырькового распространения. Это значит, что они генерируются только в том элементе, где и возникает их причина. Такое поведение вполне согласуется со способом вложения элементов управления в окнах WPF.

Например, пусть имеется панель StackPanel, а в ней содержится кнопка, и вы наводите указатель мыши на эту кнопку. При этом событие MouseEnter возникнет сначала в элементе StackPanel (при появлении указателя в пределах панели), а затем в кнопке (когда указатель попадет на нее). А при перемещении указателя мыши в сторону возникнет событие MouseLeave: сначала в кнопке, а затем в StackPanel.

Можно также реагировать на два события, которые возникают при перемещении указателя мыши: PreviewMouseMove (туннелируемое событие) и MouseMove (пузырьковое событие). Все эти события обеспечивают код одной и той же информацией: объектом MouseEventArgs. Свойства этого объекта позволяют узнать о состоянии кнопок мыши в момент возникновения события, а метод GetPosition() сообщает координаты указателя относительно указанного элемента. Ниже представлен пример, который выводит положение указателя мыши относительно формы в независимых от устройства единицах:

<Grid>
        <Grid.RowDefinitions>
            <RowDefinition></RowDefinition>
            <RowDefinition Height="auto"></RowDefinition>
        </Grid.RowDefinitions>
        <Button Background="LightBlue" MouseMove="Button_MouseMove"></Button>
        <Label Name="lblCoordinateInfo" Grid.Row="1" MinHeight="20" FontSize="14"></Label>
</Grid>
private void Button_MouseMove(object sender, MouseEventArgs e)
{
    Point pt = e.GetPosition(this);
    lblCoordinateInfo.Content = String.Format("X: {0}, Y: {1}",pt.X,pt.Y);
}
Местоположение мыши

В данном случае координаты отсчитываются от левого верхнего угла клиентской области (под строкой заголовка). На рисунке виден результат выполнения этого кода.

Класс UIElement содержит два свойства, полезных для определения местоположения указателя мыши. Свойство IsMouseOver позволяет определить, находится ли указатель мыши над элементом или одним из его потомков, а свойство isMouseDirectlyOver — выяснить, находится ли указатель мыши над самим элементом, а не над его потомком. Как правило, значения этих свойств используются в коде не для анализа и реагирования, а для создания триггеров стилей, которые автоматически изменяют элементы при перемещении указателя мыши над ними.

Щелчки кнопками мыши

Щелчки кнопками мыши подобны нажатиям клавиш на клавиатуре. Однако существуют отдельные события для левой кнопки и правой кнопки. В таблице эти события приведены в порядке их возникновения:

Хронология возникновения событий
Имя Тип маршрутизации Описание
PreviewMouseLeftButtonDown, PreviewMouseRightButtonDown Туннелирование Возникает при нажатии кнопки мыши
MouseLeftButtonDown Пузырьковое распространение То же
PreviewMouseLeftButtonUp, PreviewMouseRightButtonUp Туннелирование Возникает при отпускании кнопки мыши
MouseRightButtonUp Пузырьковое распространение То же

Помимо перечисленных, есть еще два события, которые реагируют на вращение колесика мыши: PreviewMouseWheel и MouseWheel. Все события кнопок мыши предоставляют объект MouseButtonEventArgs. Класс MouseButtonEventArgs порожден от класса MouseEventArgs (а это означает, что он содержит ту же информацию о координатах и состоянии кнопки) и добавляет несколько новых членов. Менее важными свойствами являются MouseButton (сообщает о том, какая кнопка сгенерировала событие) и ButtonState (сообщает, была ли кнопка в момент возникновения события нажата или отпущена). Более интересным свойством является ClickCount, которое сообщает, сколько раз был произведен щелчок кнопкой, позволяя различать одиночные щелчки (ClickCount имеет значение 1) и двойные щелчки (ClickCount имеет значение 2).

Захват мыши

Обычно вскоре после того, как элемент получает событие нажатия кнопки мыши, он получает и соответствующее событие отпускания этой кнопки. Однако так бывает не всегда. Например, если щелкнуть на элементе и, не отпуская кнопку мыши, переместить указатель за пределы элемента, то элемент не получит событие отпускания кнопки.

В некоторых ситуациях бывают нужны уведомления о событиях отпускания кнопки мыши, даже если указатель мыши покинул пределы элемента. Для этого нужно захватить (capture) мышь, вызвав метод Mouse.Capture() и передав ему соответствующий элемент. С этого момента вы будете получать события о нажатии и отпускании кнопок мыши — пока снова не вызовете метод Mouse.Capture() с пустой (null) ссылкой в качестве аргумента.

Пока мышь захвачена, остальные элементы не будут получать события мыши. Это означает, что пользователь не сможет щелкать кнопками мыши в других местах окна, внутри текстовых полей и т.д. Захват мыши иногда используется для реализации элементов с возможностью перетаскивания и изменения размеров.

При вызове метода Mouse.Capture() ему можно передать необязательный второй параметр. Обычно при вызове метода Mouse.Capture() используется CaptureMode.Element, что означает, что ваш элемент будет всегда получать события мыши. Однако можно передать и CaptureMode.SubTree, чтобы события мыши могли доходить до элемента, на котором был произведен щелчок кнопкой мыши, если этот элемент является потомком элемента, выполняющего захват. Это бывает полезно, если уже используется пузырьковое распространение или туннелирование события для наблюдения за событиями мыши в дочерних элементах.

В некоторых случаях захват мыши теряется не из-за действий приложения. Например, Windows может освободить мышь, если потребуется отобразить системное диалоговое окно. Это может случиться и в ситуации, если не освободить мышь после возникновения события, а пользователь переместит указатель, чтобы щелкнуть в окне другого приложения. В любом случае можно среагировать на потерю захвата мыши, обрабатывая событие LostMouseCapture для данного элемента.

Пока мышь захвачена элементом, вы не можете взаимодействовать с другими элементами. (Например, пользователь не сможет щелкнуть на другом элементе окна.) Захват мыши обычно используется в краткосрочных операциях, таких как перетаскивание.

Вместо метода Mouse.Capture() можно использовать два метода из класса UIElement: CaptureMouse() и ReleaseMouseCapture(). Достаточно просто вызвать эти методы для нужного элемента. Единственным ограничением данного подхода является то, что он не позволяет использовать параметр CaptureMode.SubTree.

Пройди тесты
Лучший чат для C# программистов