Неактивность и активность WPF

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

Есть только один недостаток: пока курсор остается в верхней части windows, событие PreProcessInput непрерывно запускается. У меня полноэкранное приложение, так что это убивает его. Любые идеи о том, как я могу обойти это поведение, были бы наиболее ценными.

 public partial class MainWindow : Window { readonly DispatcherTimer activityTimer; public MainWindow() { InitializeComponent(); InputManager.Current.PreProcessInput += Activity; activityTimer = new DispatcherTimer { Interval = TimeSpan.FromSeconds(10), IsEnabled = true }; activityTimer.Tick += Inactivity; } void Inactivity(object sender, EventArgs e) { rectangle1.Visibility = Visibility.Hidden; // Update // Console.WriteLine("INACTIVE " + DateTime.Now.Ticks); } void Activity(object sender, PreProcessInputEventArgs e) { rectangle1.Visibility = Visibility.Visible; // Update // Console.WriteLine("ACTIVE " + DateTime.Now.Ticks); activityTimer.Stop(); activityTimer.Start(); } } 

Обновить

Я мог бы сузить описанное поведение лучше (см. rectangle1.Visibility update в приведенном выше коде). Пока курсор лежит поверх windows и, например, изменяется Visibility элемента управления, PreProcessInput поднимается. Возможно, я не понимаю цель события PreProcessInput и когда он срабатывает. MSDN здесь не очень помог.

У нас была аналогичная потребность в нашем программном обеспечении … это приложение WPF, а также как функция безопасности – клиент может настроить время, когда их пользователь будет отключен, если они не работают.

Ниже приведен class, который я сделал для переноса кода Idle Detection (который использует встроенные функции Windows).

У нас просто есть отметка таймера за 1 секунду, чтобы проверить, превышает ли время простоя заданный порог … принимает 0 CPU.

Во-первых, вот как использовать код:

 var idleTime = IdleTimeDetector.GetIdleTimeInfo(); if (idleTime.IdleTime.TotalMinutes >= 5) { // They are idle! } 

Вы можете использовать это, а также убедиться, что ваше полноэкранное приложение WPF «сфокусировано» для достижения ваших потребностей:

 using System; using System.Runtime.InteropServices; namespace BlahBlah { public static class IdleTimeDetector { [DllImport("user32.dll")] static extern bool GetLastInputInfo(ref LASTINPUTINFO plii); public static IdleTimeInfo GetIdleTimeInfo() { int systemUptime = Environment.TickCount, lastInputTicks = 0, idleTicks = 0; LASTINPUTINFO lastInputInfo = new LASTINPUTINFO(); lastInputInfo.cbSize = (uint)Marshal.SizeOf(lastInputInfo); lastInputInfo.dwTime = 0; if (GetLastInputInfo(ref lastInputInfo)) { lastInputTicks = (int)lastInputInfo.dwTime; idleTicks = systemUptime - lastInputTicks; } return new IdleTimeInfo { LastInputTime = DateTime.Now.AddMilliseconds(-1 * idleTicks), IdleTime = new TimeSpan(0, 0, 0, 0, idleTicks), SystemUptimeMilliseconds = systemUptime, }; } } public class IdleTimeInfo { public DateTime LastInputTime { get; internal set; } public TimeSpan IdleTime { get; internal set; } public int SystemUptimeMilliseconds { get; internal set; } } internal struct LASTINPUTINFO { public uint cbSize; public uint dwTime; } } 

Я мог бы выяснить, что вызвало описанное поведение.

Например, когда изменяется Visibility элемента управления, событие PreProcessInputEventArgs.StagingItem.Input с помощью PreProcessInputEventArgs.StagingItem.Input типа InputReportEventArgs .

Поведение можно избежать, отфильтровав InputEventArgs для типов MouseEventArgs и KeyboardEventArgs в событии OnActivity и проверить, не нажата ли кнопка мыши, а положение курсора по-прежнему совпадает с положением приложения.

 public partial class MainWindow : Window { private readonly DispatcherTimer _activityTimer; private Point _inactiveMousePosition = new Point(0, 0); public MainWindow() { InitializeComponent(); InputManager.Current.PreProcessInput += OnActivity; _activityTimer = new DispatcherTimer { Interval = TimeSpan.FromMinutes(5), IsEnabled = true }; _activityTimer.Tick += OnInactivity; } void OnInactivity(object sender, EventArgs e) { // remember mouse position _inactiveMousePosition = Mouse.GetPosition(MainGrid); // set UI on inactivity rectangle.Visibility = Visibility.Hidden; } void OnActivity(object sender, PreProcessInputEventArgs e) { InputEventArgs inputEventArgs = e.StagingItem.Input; if (inputEventArgs is MouseEventArgs || inputEventArgs is KeyboardEventArgs) { if (e.StagingItem.Input is MouseEventArgs) { MouseEventArgs mouseEventArgs = (MouseEventArgs)e.StagingItem.Input; // no button is pressed and the position is still the same as the application became inactive if (mouseEventArgs.LeftButton == MouseButtonState.Released && mouseEventArgs.RightButton == MouseButtonState.Released && mouseEventArgs.MiddleButton == MouseButtonState.Released && mouseEventArgs.XButton1 == MouseButtonState.Released && mouseEventArgs.XButton2 == MouseButtonState.Released && _inactiveMousePosition == mouseEventArgs.GetPosition(MainGrid)) return; } // set UI on activity rectangle.Visibility = Visibility.Visible; _activityTimer.Stop(); _activityTimer.Start(); } } } 

Вместо того, чтобы слушать PreProcessInput , вы пробовали PreviewMouseMove ?

Я реализую решение в classе IdleDetector. Я немного улучшил код. Детектор Iddle бросает IsIdle. Это может быть перехват! Это так! Я жду некоторых комментариев.

 public class IdleDetector { private readonly DispatcherTimer _activityTimer; private Point _inactiveMousePosition = new Point(0, 0); private IInputElement _inputElement; private int _idleTime = 300; public event EventHandler IsIdle; public IdleDetector(IInputElement inputElement, int idleTime) { _inputElement = inputElement; InputManager.Current.PreProcessInput += OnActivity; _activityTimer = new DispatcherTimer { Interval = TimeSpan.FromSeconds(idleTime), IsEnabled = true }; _activityTimer.Tick += OnInactivity; } public void ChangeIdleTime(int newIdleTime) { _idleTime = newIdleTime; _activityTimer.Stop(); _activityTimer.Interval = TimeSpan.FromSeconds(newIdleTime); _activityTimer.Start(); } void OnInactivity(object sender, EventArgs e) { _inactiveMousePosition = Mouse.GetPosition(_inputElement); _activityTimer.Stop(); IsIdle?.Invoke(this, new EventArgs()); } void OnActivity(object sender, PreProcessInputEventArgs e) { InputEventArgs inputEventArgs = e.StagingItem.Input; if (inputEventArgs is MouseEventArgs || inputEventArgs is KeyboardEventArgs) { if (e.StagingItem.Input is MouseEventArgs) { MouseEventArgs mouseEventArgs = (MouseEventArgs)e.StagingItem.Input; // no button is pressed and the position is still the same as the application became inactive if (mouseEventArgs.LeftButton == MouseButtonState.Released && mouseEventArgs.RightButton == MouseButtonState.Released && mouseEventArgs.MiddleButton == MouseButtonState.Released && mouseEventArgs.XButton1 == MouseButtonState.Released && mouseEventArgs.XButton2 == MouseButtonState.Released && _inactiveMousePosition == mouseEventArgs.GetPosition(_inputElement)) return; } _activityTimer.Stop(); _activityTimer.Start(); } } } 
  • Как использовать GWT EventBus
  • Когда происходит событие «размытия», как я могу узнать, какой элемент фокуса пошел * на *?
  • Когда используется пул streamов?
  • Порядок событий «Form.Load», «Form.Shown» и «Form.Activated» в Windows Forms
  • Повторно используемый шаблон для преобразования события в задачу
  • Как события вызывают утечку памяти на C # и как облегчить работу слабых ссылок?
  • Событие изменения триггера () при установке значения с помощью функции val ()
  • Пользовательские события в jQuery?
  • Использование lambda-выражений для обработчиков событий
  • Событие jquery live для добавления элементов dom
  • Как захватить щелчок мышью по элементу в ListBox в WPF?
  • Давайте будем гением компьютера.