如何在Windows应用程序中设置用户空闲或不活动时的定时器。
Posted
tags:
篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了如何在Windows应用程序中设置用户空闲或不活动时的定时器。相关的知识,希望对你有一定的参考价值。
我在Windows窗体中有一个关于设置用户闲置或不活动时的定时器的问题。我需要在任何鼠标事件上设置定时器。如果用户做任何时刻,那么我需要重置定时器。所以这是需求。下面是代码。
using System;
using System.Windows.Forms;
using Timer = System.Windows.Forms.Timer;
namespace FormsTimerSetup.Globals
{
public class SetApplicationTimeOut : Form
{
#region
/// <summary>
/// Private Timer Property
/// </summary>
private static Timer _timer;
/// <summary>
/// Timer Property
/// </summary>
public static Timer Timer
{
get
{
return _timer;
}
set
{
if (_timer != null)
{
_timer.Tick -= Timer_Tick;
}
_timer = value;
if (_timer != null)
{
_timer.Tick += Timer_Tick;
}
}
}
#endregion
#region Events
public event EventHandler UserActivity;
#endregion
#region Constructor
/// <summary>
/// Default/Parameterless SetApplicationTimeOut Constructor
/// </summary>
public SetApplicationTimeOut()
{
KeyPreview = true;
FormClosed += ObservedForm_FormClosed;
MouseMove += ObservedForm_MouseMove;
KeyDown += ObservedForm_KeyDown;
}
#endregion
#region Inherited Methods
/// <summary>
///
/// </summary>
/// <param name="e"></param>
protected virtual void OnUserActivity(EventArgs e)
{
// Invoking the UserActivity delegate
UserActivity?.Invoke(this, e);
}
/// <summary>
///
/// </summary>
public void SetTimeOut()
{
// postpone auto-logout by 30 minutes
_timer = new Timer
{
Interval = (30 * 60 * 1000) // Timer set for 30 minutes
};
Application.Idle += Application_Idle;
_timer.Tick += new EventHandler(Timer_Tick);
}
#endregion
#region Private Methods
/// <summary>
///
/// </summary>
/// <param name="sender"></param>
/// <param name="e"></param>
private void ObservedForm_MouseMove(object sender, MouseEventArgs e)
{
OnUserActivity(e);
}
/// <summary>
///
/// </summary>
/// <param name="sender"></param>
/// <param name="e"></param>
private void ObservedForm_KeyDown(object sender, KeyEventArgs e)
{
OnUserActivity(e);
}
/// <summary>
///
/// </summary>
/// <param name="sender"></param>
/// <param name="e"></param>
private void ObservedForm_FormClosed(object sender, FormClosedEventArgs e)
{
FormClosed -= ObservedForm_FormClosed;
MouseMove -= ObservedForm_MouseMove;
KeyDown -= ObservedForm_KeyDown;
}
/// <summary>
///
/// </summary>
/// <param name="sender"></param>
/// <param name="e"></param>
private static void Application_Idle(object sender, EventArgs e)
{
_timer.Stop();
_timer.Start();
}
/// <summary>
///
/// </summary>
/// <param name="sender"></param>
/// <param name="e"></param>
private static void Timer_Tick(object sender, EventArgs e)
{
_timer.Stop();
Application.Idle -= Application_Idle;
MessageBox.Show("Application Terminating");
Application.Exit();
}
#endregion
}
}
我已经实现了代码,但不确定它是否是正确的方式来做。
任何线索将被感激。谢谢你看完帖子,注意安全!
问:"我需要在任何鼠标事件上设置定时器......如果用户做出任何动作,那么我需要重置定时器......任何线索都将被感激。"
答:我试着提供一些线索,希望你觉得有用。你说你想让MouseMove事件来重置计时器,但是有一个问题:任何时候子控件有焦点的时候,都是子控件收到鼠标事件,而主窗体没有。这个问题是可以解决的。
简短的答案是:"实现子控件的MouseMove事件。"实现 IMessageFilter 接口上的主窗口类,这样当检测到鼠标移动时,定时器就会被重置。" 在主窗口类上添加一个 信息过滤 可以拦截鼠标信息 之前 它们被发送到重点控制。
所以,现在我必须给你所有的细节,所以这里是长答案。首先要加入... IMessageFilter 接口到我们的主Form1,就像这样。
public partial class Form1 : Form, IMessageFilter
IMessageFilter要求我们的类只需要实现一个方法。
public bool PreFilterMessage(ref Message m)
{
switch (m.Msg)
{
case WM_MOUSEMOVE:
// vvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvv
// Commit f9367d7c added at OP's request
case WM_KEYDOWN:
// This makes WakeUp persist if user is typing in the textbox.
// ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
TimeOutState = TimeOutState.WakeUp;
break;
}
return false; // Do not suppress downstream message
}
const int // WinOS Messages
WM_KEYDOWN = 0x0100,
WM_MOUSEMOVE = 0x0200;
你可以看到,现在任何鼠标移动都会将我们的应用程序的TimeOutState设置为 "WakeUp"。
enum TimeOutState{ WakeUp, Sleeping, Warning, Exit }
我们只需要一个定时器,定时器的每一个tick间隔(这里设置为5秒)就会减少一个状态。如果鼠标不动,它就会一路递减,最后退出。
下面是一个60秒的 视频 的运行应用程序60秒。你可以看到每5秒或鼠标移动时发生的变化。如果您想运行该样本,您可以 克隆 的最新提交。
下面是其余的细节。
MessageFilter需要被连接。因为我们需要我们的Form有它的窗口句柄,所以我们在这里做这个并启动定时器。
protected override void OnHandleCreated(EventArgs e) { base.OnHandleCreated(e); // When our main window is ready for messages, add the MessageFilter Application.AddMessageFilter(this); // ...and start the timer for the first time. TimeOutState = TimeOutState.WakeUp; }
我们需要实例化定时器,但在CTor中只需要一次。
public Form1() { InitializeComponent(); _wdt = new Timer(); _wdt.Interval = 5000; // Use a very short time-out for this demo _wdt.Tick += _wdt_Tick; } Timer _wdt; // Watch-Dog Timer
我们需要处理Timer.Tick。
private void _wdt_Tick(object sender, System.EventArgs e) { // A tick reduces the TimeOutState by 1 TimeOutState = (TimeOutState)(TimeOutState - 1); }
最后,处理TimeOutState的状态变化,并显示我们的消息。
TimeOutState TimeOutState { get => _timeOutState; set { switch (value) { case TimeOutState.WakeUp: _wdt.Stop(); _wdt.Start(); break; case TimeOutState.Exit: _wdt.Stop(); Application.Exit(); return; } if (value != _timeOutState) // If state changes, write message { Debug.WriteLine(value.ToString(), _timeOutState.ToString()); // In a timer callback that changes the UI, it's // best to post the action in the message queue. BeginInvoke((MethodInvoker)delegate { textBox1.AppendText(_timeOutState.ToString()); if (TimeOutState == TimeOutState.Warning) { textBox1.AppendText( ": Closing in " + (_wdt.Interval / 1000).ToString() + " seconds."); } textBox1.AppendText(Environment.NewLine); textBox1.Select(textBox1.TextLength, 0); }); } _timeOutState = value; } } TimeOutState _timeOutState = (TimeOutState)(-1); // Initialize to invalid state
我使用了 IMessageFilter 在我自己的应用程序中非常可靠,我有信心向你建议,作为回答你的帖子的一个选择。
我不会深入研究你的代码,但我想直接解决这个问题。我认为在这种情况下,一个 "迂回 "的方法是可行的,例如,你可以在鼠标移动时检查并与初始位置进行比较。
例如,你可以在鼠标移动时检查并与初始位置进行比较。
在Initialize Component()上面添加以下内容。
GlobalMouseHandler gmh = new GlobalMouseHandler();
gmh.TheMouseMoved += new MouseMovedEvent(gmh_TheMouseMoved);
Application.AddMessageFilter(gmh);
然后添加这个。
void gmh_TheMouseMoved()
{
if(XY==false)
{
MouseX = Convert.ToInt32(Cursor.Position.X);
MouseY = Convert.ToInt32(Cursor.Position.Y);
}
else
{
MouseX1 = Convert.ToInt32(Cursor.Position.X);
MouseY1 = Convert.ToInt32(Cursor.Position.Y);
XY = true;
if(MouseX1==MouseX && MouseY1==MouseY)
{
if(yourTimerNameHere.Enabled==false)
{
yourTimerNameHere.Start();
}
}
else
{
yourTimerNameHere.Stop();
yourTimerNameHere.Start();
}
}
}
在你的窗体类之外添加这个。
public delegate void MouseMovedEvent();
public class GlobalMouseHandler : IMessageFilter
{
private const int WM_MOUSEMOVE = 0x0200;
public event MouseMovedEvent TheMouseMoved;
public bool PreFilterMessage(ref Message m)
{
if (m.Msg == WM_MOUSEMOVE)
{
if (TheMouseMoved != null)
{
TheMouseMoved();
}
}
return false;
}
}
接下来创建4个ints,分别命名为MouseX=0、MouseY=0、MouseX1=0和MouseY1=0,以及一个bool XY=false。
所以实际上,每当光标移动时,位置就会被记录下来,并与下一个位置进行比较。所以你可以检查鼠标是否空闲!
请注意,我还没有测试过这段代码,所以如果有任何错误,请随时回访。
以上是关于如何在Windows应用程序中设置用户空闲或不活动时的定时器。的主要内容,如果未能解决你的问题,请参考以下文章