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)
Mar*_*erl 19
我可以弄清楚导致所述行为的原因.
例如,当Visibility
控件的更改时,PreProcessInput
将使用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();
}
}
}
Run Code Online (Sandbox Code Playgroud)