WPF不活动和活动

Mar*_*erl 32 .net c# wpf events

我正在尝试处理WPF应用程序中的用户不活动和活动,以淡入淡出某些内容.经过大量的研究,我决定采用(至少在我看来)非常优雅的解决方案Hans Passant在这里发布.

只有一个缺点:只要光标停留在窗口顶部,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();
    }
}
Run Code Online (Sandbox Code Playgroud)

更新

我可以更好地缩小所描述的行为(请参阅rectangle1.Visibility上面代码中的更新).只要光标停留在窗口的顶部并且例如Visibility控件的更改,PreProcessInput就会引发.也许我误解了PreProcessInput事件的目的以及事件何时触发.MSDN在这里不是很有帮助.

Tim*_*uri 41

我们对软件有类似的需求......它也是一个WPF应用程序,作为一个安全功能 - 客户端可以配置一个时间,如果用户空闲,他们将被注销.

下面是我用来封装空闲检测代码的类(它使用了内置的Windows功能).

我们只需要1秒的计时器滴答来检查空闲时间是否大于指定的阈值...需要0 CPU.

首先,这是如何使用代码:

var idleTime = IdleTimeDetector.GetIdleTimeInfo();

if (idleTime.IdleTime.TotalMinutes >= 5)
{
    // They are idle!
}
Run Code Online (Sandbox Code Playgroud)

您可以使用此功能,并确保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;
    }
}
Run Code Online (Sandbox Code Playgroud)

  • 该类正在检查整个系统的空闲时间,而不仅仅是 wpf 应用程序。理想情况下,如果用户说最后一小时在使用 ms word,那么我想关闭应用程序,因此 wpf 不集中。我怎样才能做到这一点? (2认同)

Mar*_*erl 19

我可以弄清楚导致所述行为的原因.

例如,当Visibility控件的更改时,PreProcessInput将使用PreProcessInputEventArgs.StagingItem.Input该类型引发事件InputReportEventArgs.

可以通过过滤来避免行为InputEventArgs的类型MouseEventArgsKeyboardEventArgs在所述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();
        }
    }
}
Run Code Online (Sandbox Code Playgroud)