【问题标题】:How can I trigger an auto-logout within a Windows Forms Application?如何在 Windows 窗体应用程序中触发自动注销?
【发布时间】:2011-10-09 01:58:17
【问题描述】:

我有一个 Windows 应用项目,用户可以使用他们的用户名和密码登录。我想这样当用户登录时,我会得到登录时间,如果用户在 30 分钟内不使用应用程序,应用程序会将用户再次发送到登录屏幕。我怎样才能做到这一点?

【问题讨论】:

  • timer 怎么样?
  • 我同意科迪·格雷的观点。但从用户的角度来看,这会很烦人......
  • 不,我认为这还不够,必须有其他东西控制用户操作键盘和鼠标操作。因为我的应用程序中有很多表单。Form_Active 事件和计时器类对此不够用。

标签: c# winforms


【解决方案1】:

编辑:亚当完全正确,我误解了这个问题,所以我删除了我原来的答案。

要监控用户活动,您可以创建一个自定义的基于Form 的类,您的应用程序表单将从该类继承。在那里您可以订阅 MouseMove 和 KeyDown 事件(将 KeyPreview 属性设置为 true),只要用户处于活动状态,就会引发其中任何一个事件。然后,您可以创建一个System.Threading.Timer,并将到期时间设置为 30 分钟,并在检测到用户活动时使用 Change() 方法将其推迟。

这是下面的一个示例实现:ObservedForm 写得比较笼统,以便您更容易看到模式。

public class ObservedForm : Form
{
     public event EventHandler UserActivity;

     public ObservedForm()
     {
         KeyPreview = true;

         FormClosed += ObservedForm_FormClosed;
         MouseMove += ObservedForm_MouseMove;
         KeyDown += ObservedForm_KeyDown;
     }

     protected virtual void OnUserActivity(EventArgs e)
     {
         var ua = UserActivity;
         if(ua != null)
         {
              ua(this, e);
         }
     }

     private void ObservedForm_MouseMove(object sender, MouseEventArgs e)
     {
          OnUserActivity();
     }

     private void ObservedForm_KeyDown(object sender, KeyEventArgs e)
     {
          OnUserActivity();
     }

     private void ObservedForm_FormClosed(object sender, FormClosedEventArgs e)
     {
         FormClosed -= ObservedForm_FormClosed;
         MouseMove -= ObservedForm_MouseMove;
         KeyDown -= ObservedForm_KeyDown;
     }
}

现在您可以订阅 UserActivity 事件,并执行您想要的逻辑,例如:

private System.Threading.Timer timer = new Timer(_TimerTick, null, 1000 * 30 * 60, Timeout.Infinite);
private void _OnUserActivity(object sender, EventArgs e)
{
     if(timer != null)
     {
         // postpone auto-logout by 30 minutes
         timer.Change(1000 * 30 * 60, Timeout.Infinite);
     }
}

private void _TimerTick(object state)
{
    // the user has been inactive for 30 minutes; log him out
}

希望这会有所帮助。

编辑#2:为了清楚起见,重新表述了部分解释,并将 FormClosing 事件的使用更改为 FormClosed。

【讨论】:

  • 一个限制是计时器忽略当前用户操作并假定用户在超时发生之前只有一个设置的窗口。超时通常是由于用户不活动而发生的,在您的示例中没有考虑到这一点。
  • @Adam:你说得对,我没有仔细阅读这个问题。查看我编辑的帖子。
  • 我找到了另一种方法来解决这个问题。而且你的方法看起来不错。谢谢。
  • 我很想详细了解这对自定义事件的新手来说是如何工作的。
  • 很好的解决方案!
【解决方案2】:

这是解决此问题的简单方法。它运行良好。

using System;
using System.Windows.Forms;
namespace WindowsApplication1 {
    public partial class Form1 : Form, IMessageFilter {
        private Timer mTimer;
        private int mDialogCount;
        public Form1() {
            InitializeComponent();
            mTimer = new Timer();
            mTimer.Interval = 2000;
            mTimer.Tick += LogoutUser;
            mTimer.Enabled = true;
            Application.AddMessageFilter(this);
        }

        public bool PreFilterMessage(ref Message m) {
            // Monitor message for keyboard and mouse messages
            bool active = m.Msg == 0x100 || m.Msg == 0x101;  // WM_KEYDOWN/UP
            active = active || m.Msg == 0xA0 || m.Msg == 0x200;  // WM_(NC)MOUSEMOVE
            active = active || m.Msg == 0x10;  // WM_CLOSE, in case dialog closes
            if (active) {
                if (!mTimer.Enabled) label1.Text = "Wakeup";
                mTimer.Enabled = false;
                mTimer.Start();
            }
            return false;
        }

        private void LogoutUser(object sender, EventArgs e) {
            // No activity, logout user
            if (mDialogCount > 0) return;
            mTimer.Enabled = false;
            label1.Text = "Time'z up";
        }

        private void button1_Click(object sender, EventArgs e) {
            mDialogCount += 1;
            Form frm = new Form2();
            frm.ShowDialog();
            mDialogCount -= 1;
            mTimer.Start();
        }
    }
}

【讨论】:

  • 为什么在有活动时禁用计时器?具体来说,mTimer.Enabled = false;if (active) 块内?
  • 这是一个没什么特别的例子。它的重启计时器:),我改变了逻辑。 if (active) then disable timer else timer start..当定时器滴答事件引发调用LoginDialog如果用户可以登录成功...这样循环。
  • 这对我来说没有任何意义。如果您正在启动它(调用它的Start 方法),似乎您应该将计时器的Enabled 属性设置为“true”,但如果代码适合您,无论如何。
  • 如果有活动我不想启动计时器因为在计时器滴答事件中有 LoginDialog 调用操作,所以它必须启用 false,如果没有活动则计时器必须继续然后调用 LoginDialog 进行登录操作并等待登录。成功。是的,它工作得很好。Ty Cody Gray
  • 嘿,这是我的代码。抄袭自social.msdn.microsoft.com/Forums/en-US/…
【解决方案3】:

您必须为所有表单创建一个基类,它将拦截任何用户活动并存储上次活动时间。每次用户点击某事时,您都必须检查上次活动日期并确定是否太久。

目前我不知道如何拦截,但我很确定这是可能的(也许使用 Windows 消息?)

【讨论】:

    【解决方案4】:

    1.st: 用户登录,将时间戳存储在某处(例如,这个 unix 时间戳“1294230230”表示大约是 2011 年 1 月 5 日 12:24)
    int sess_creation_time = now(); *让我们说'now()'函数返回当前的unix时间戳

    2.nd: 当用户尝试执行任何操作时,捕获此尝试的时间戳。
    int temp_time = now();
    现在,只需将这些值与您想要的自动注销限制进行比较。

    // 这里比较 // a, temp_time - sess_creation_time => 差异,不活动时间 // 60*30 -> 60 秒 * 30 -> 30 分钟 if( (temp_time - sess_creation_time) > (60*30) ) { // 不活动时间大于允许的时间,在此处注销 登出(); } 别的 { // session 仍然有效,不要忘记更新它的创建时间 sess_creation_time = 现在(); }

    别忘了,这不是用 C/C++ 或 C# 编写的,但逻辑保持不变 ;-)
    希望对你有所帮助

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2011-07-01
      • 1970-01-01
      相关资源
      最近更新 更多