Почему все события WPF Touch теперь запускаются только как MouseEvents? - PullRequest
0 голосов
/ 02 марта 2020

Есть ли какой-то неясный способ, которым я мог бы глобально (случайно) отключить все события Touch во всем моем приложении WPF одновременно - так, чтобы они были "повышены" до событий мыши? Есть ли где-нибудь глобальный флаг WPF, который их отключает? Если да, может ли кто-нибудь дать мне представление о том, что это может быть?

Подробное объяснение:

У меня есть настольное приложение WPF (. NET Core 3.1 ) работает на поверхности MS. В течение почти 2 лет он работал нормально с обработчиками касания и мыши; Если пользователь щелкнул мышью, обработчик мыши был вызван. Если пользователь касался их пальцем, вызывался обработчик ManipulationEvent (или TouchEvent).

Но недавно я увидел странное поведение и, наконец, понял, что каждое отдельное событие манипуляции касанием «продвигается» к событию мыши до того, как он достиг любого из моих обработчиков касания / манипуляции.

Например, вот стиль, который я применяю к объектам Path в одном из моих представлений:

<Style x:Key="ShapeDragPathStyle" TargetType="{x:Type Path}">
    <Setter      Property="Cursor"           Value="Hand" />
    <EventSetter Event="MouseLeftButtonDown" Handler="Shape_OnLeftButtonDown" />
    <EventSetter Event="MouseMove"           Handler="Shape_OnMouseMove" />
    <EventSetter Event="MouseLeftButtonUp"   Handler="Shape_OnMouseLeftButtonUp" />
    <EventSetter Event="TouchDown"           Handler="Shape_OnTouchDown" />
</Style>

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

Для завершения приведу список всех событий касания, для которых я объявил обработчики в различных местах моего XAML и которые я использовал в течение длительного времени.

ManipulationStarting
ManipulationStarted 
ManipulationDelta
ManipulationCompleted
TouchUp
TouchDown
PreviewTouchDown

Ни один из этих обработчиков больше не вызывается. Я буквально пошел и ставил точки останова на каждом из них, не важно, где они. Неважно, если у меня есть IsManipulationEnabled="True" на них или нет. Эквивалент мыши всегда вызывает вызванные попадания.

Также это не похоже на что-то в Windows настройках. Я проверил, что это происходит на нескольких машинах MS Surface, и что это происходит только в моем приложении; Я создал простое тестовое приложение. NET Core 3.1 и добавил обработчик ManipulationStarting, и это сработало.

Есть идеи, что мне следует искать?

(я уверен, что почувствую себя глупо, когда узнаю, но уже чувствую ...)

1 Ответ

0 голосов
/ 02 марта 2020

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

Короче говоря, виновник был System.Management.ManagementEventWatcher

Я хотел, чтобы мое приложение было уведомлено, когда устройство USB был подключен. Таким образом, я создал ManagementEventWatcher, который следил за такими событиями

Watcher = new ManagementEventWatcher(
    new ManagementScope("root\\CIMV2"),
    new WqlEventQuery()
    {
        EventClassName = "Win32_DeviceChangeEvent",
        Condition      = "EventType = 2 OR EventType = 3",
    });

Watcher.EventArrived += (sender, args) => { DeviceChanged?.Invoke(this, true); };

Watcher.Start();  // THIS WAS THE PROBLEM

Вызов Start() в основном потоке пользовательского интерфейса, похоже, меняет то, как основной поток обрабатывает оконные сообщения. Весь callstack выглядит иначе, когда я делаю это. Входящие сенсорные сообщения go прямо в обработчики мыши, прежде чем что-либо даже достигнет моего кода.

Когда я комментирую вызов Start(), все сенсорные обработчики вызываются снова.

Поэтому я попытался перевести вызов на Start() в фоновом потоке:

Task.Run(() => Watcher.Start());

А теперь все отлично работает. Я не уверен, что это окончательный ответ - я мог бы даже захотеть создать свой собственный выделенный поток, чтобы избежать путаницы с какими-либо потоками пула потоков - но, конечно, все.

Так что может показаться, что ManagementEventWatcher - это нечто лучше всего не использовать потоки пользовательского интерфейса, по крайней мере, в WPF

...