Странные перекрестные помехи событий: мышь и клавиатура, WPF и Rx?

Я написал действительно крошечную программу WPF + Rx в VS 2010, и у нее есть неожиданное поведение - по-видимому, улавливание событий с нажатой клавишей Alt в наблюдаемых событиях мыши. Буду признателен за совет по любому из

  1. что конкретно не так
  2. идеи или инструменты о том, как диагностировать это самостоятельно [например, есть ли какие-то инструменты, которые используют код для отслеживания и регистрации всех запускаемых событий, чтобы я мог более четко видеть, что происходит?]
  3. как понять поведение - это «задумано»? Я неправильно использую WPF, Rx или и то, и другое?
  4. как получить поведение, которое я бы предпочел, описано ниже

Во-первых, что он делает правильно, так это запускает наблюдателей за перемещением мыши, начиная с мыши вниз и заканчивая ее движением вверх. Конкретный тестовый наблюдатель, который у меня есть, просто помещает правильные координаты mouseDown + mouseUp в заголовок окна (см. Ниже код + XAML).

Странность начинается, если я нажимаю и отпускаю клавишу alt, когда мышь опущена. Кажется, что это немедленно останавливает наблюдателей событий mouseMove. Теперь, если я отпущу mouseButton, наблюдатели событий mouseMove снова запустятся и продолжат, пока я не сгенерирую новый mouseDown или снова не нажму и не отпущу alt. Более того, если я пройду через эту последовательность, а именно

mouseDown
mouseMove
alt-key down
alt-key up
mouseUp
alt-key down
alt-key up

а затем нормальный

mouseDown
mouseMove

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

Мне не удалось сделать это с помощью других клавиш, кроме alt, что углубляет тайну.

Желаемое поведение может быть

  1. либо явная проверка состояния клавиши alt в обработчиках перемещения мыши
  2. или отдельные потоки событий для событий keyDown и keyUp, и я выясню чередование в моем коде

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

(ПРИМЕЧАНИЕ: добавьте ссылки на System.coreex, System.Reactive и System.Interactive)

using System;
using System.Collections.Generic;
using System.Linq;
using System.Windows;
using System.Windows.Input;

namespace DownAndMoveTest
{
    public partial class MainWindow : Window
    {
        public MainWindow()
        {
            InitializeComponent();
            (from mDown in this.GetLeftMouseDownObservable().
                 Do(e => this.Title = "DOWN: " + e.EventArgs.GetPosition(this).ToString())
             let mDownP = mDown.EventArgs.GetPosition(this)
             from mMove in this.GetMouseMoveObservable().TakeUntil(this.GetLeftMouseUpObservable())
             select new
             {
                 D = mDownP,
                 M = mMove.EventArgs.GetPosition(this)
             }).Subscribe(ps =>
             {
                 this.Title = String.Format(
                   "Window MouseDown({0:G}, {1:G}), MouseMove({2:G}, {3:G})",
                   ps.D.X, ps.D.Y,
                   ps.M.X, ps.M.Y);
             });
        }
    }
    public static partial class UIElementExtensions
    {
        public static IObservable<IEvent<MouseButtonEventArgs>>
            GetLeftMouseDownObservable(this UIElement uiElement)
        {
            return Observable.FromEvent<MouseButtonEventHandler, MouseButtonEventArgs>(
               h => new MouseButtonEventHandler(h),
               h => uiElement.MouseLeftButtonDown += h,
               h => uiElement.MouseLeftButtonDown -= h);
        }

        public static IObservable<IEvent<MouseEventArgs>>
            GetMouseMoveObservable(this UIElement uiElement)
        {
            return Observable.FromEvent<MouseEventHandler, MouseEventArgs>(
               h => new MouseEventHandler(h),
               h => uiElement.MouseMove += h,
               h => uiElement.MouseMove -= h);
        }

        public static IObservable<IEvent<MouseButtonEventArgs>>
            GetLeftMouseUpObservable(this UIElement uiElement)
        {
            return Observable.FromEvent<MouseButtonEventHandler, MouseButtonEventArgs>(
               h => new MouseButtonEventHandler(h),
               h => uiElement.MouseLeftButtonUp += h,
               h => uiElement.MouseLeftButtonUp -= h);
        }
    }
}

и его XAML

<Window x:Class="DownAndMoveTest.MainWindow"
    xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
    xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
    Title="MainWindow" Height="350" Width="525">
    <Grid>
    </Grid>
</Window>

person Reb.Cabin    schedule 26.11.2010    source источник


Ответы (1)


В вашем приложении есть главное меню? Нажатие клавиши alt фокусирует строку меню, а повторное нажатие alt возвращает фокус на то, что было в фокусе раньше. Это объяснило бы функциональность, которую вы видите. (Это не похоже на проблему с Rx)

person Richard Szalay    schedule 27.11.2010
comment
Я посмотрю на это, Ричард. Я не делал ничего, чтобы специально помещать меню в приложение (XAML выше - это все), но вся инфраструктура команд WPF, похоже, активна и, возможно, это делает. Инструмент слежки мне немного помогает. blois.us/snoop. - person Reb.Cabin; 28.11.2010