C# Как долго пользователь был неактивен
Некоторые предыстории: я пишу приложение с несколькими формами и т. Д. Пользователи должны войти в систему, чтобы использовать большинство функций, и до сих пор это работало нормально. Однако теперь клиент запросил, чтобы пользователь вышел из системы после определенного количества неактивного времени. Проблема в том, что пользователь все еще может быть активным на компьютере, но не в моем приложении. Чтобы было ясно, я должен выйти из системы, когда он неактивен в моем приложении, даже если он все еще взаимодействует с рабочим столом.
Сначала я подумал, что это будет довольно просто. Просто запомните время последнего действия, постоянно сравнивайте его по таймеру с текущим временем и выйдите из системы, если время прошло больше, чем разрешенное время. Однако я понял, что выяснить время последнего действия может быть не так просто...
Конечно, я мог бы скопировать вставить что-то вроде
Program.LastActionTime = DateTime.Now;
в каждом событии OnChange, OnClick и т. д.... Однако не только то, что это будет большой объем работы из-за размера приложения... Это также будет очень плохой практикой, и я уверен, что это будет забыл хотя бы один раз, сделав все это ненадежным (и, если он будет сломан, ошибку будет практически невозможно воспроизвести!)
Так есть ли лучший способ?
6 ответов
В вашем файле Program.CS вы можете обработать событие Application.Idle и сбросить там таймер. Увидеть:
http://msdn.microsoft.com/en-us/library/system.windows.forms.application.idle.aspx
Один из подходов, который я использовал в прошлом, - создать MessageFilter в форме приложения и проверить наличие определенных типов событий, которые указывают на активность пользователя:
public class UserActivityFilter : IMessageFilter
{
// Define WinAPI window message values (see pinvoke.net)
private int WM_LBUTTONDOWN = 0x0201;
private int WM_MBUTTONDOWN = 0x0207;
private int WM_RBUTTONDOWN = 0x0204;
private int WM_MOUSEWHEEL = 0x020A;
private int WM_MOUSEMOVE = 0x0200;
private int WM_KEYDOWN = 0x0100;
public bool PreFilterMessage(ref Message m)
{
if (m.Msg == WM_LBUTTONDOWN || m.Msg == WM_MBUTTONDOWN || m.Msg == WM_RBUTTONDOWN || m.Msg == WM_MOUSEWHEEL || m.Msg == WM_MOUSEMOVE || m.Msg == WM_KEYDOWN)
{
//User activity has occurred
// Reset a flag / timer etc.
}
return false;
}
}
Затем в методе Main() формы ДО вызова функции Run():
Application.AddMessageFilter(new UserActivityFilter());
Одно предупреждение, добавление сложного фильтра сообщений или добавление нескольких отдельных фильтров может замедлить отзывчивость вашего приложения.
Вы можете переопределить WndProc
, Обновить Program.LastActionTime
на каждом соответствующем Keyboard/Mouse
сообщение о событии
В общем, было бы лучше всего получить эту информацию из логики вашего приложения вместо необработанного пользовательского ввода, но я предполагаю, что у вас нет гибкой инфраструктуры (возможно, с использованием шаблона команды), которая могла бы предоставить эту информацию.
Поэтому я предлагаю просто зарегистрировать обработчики в главной форме - если вы получаете щелчки или ключевые события (для этого включите Form.KeyPreview), ваш пользователь активен, и вы можете сбросить время бездействия.
Перехватить обработчик событий для событий MouseMove и KeyPressed, а затем проверить фокус внутри этого события?
Вы можете создать базовый класс, от которого наследуются все ваши оконные формы. В базовом классе вы проверяете и сбрасываете свое время ожидания при каждом нажатии или нажатии клавиши.