2011-02-10 91 views
28

我試圖處理用戶活動和活動在WPF應用程序褪色一些東西進出。經過大量的研究,我決定去(至少在我看來)非常優雅的解決方案Hans Passant發佈了hereWPF活動和活動

這裏只有一個缺點:只要光標停留在窗口頂部,該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(); 
    } 
} 

更新

我能縮小所描述的行爲更好(見上面的代碼rectangle1.Visibility更新)。只要光標停留在窗口的頂部,並且例如控件的Visibility被更改,則PreProcessInput就會升起。也許我誤解了PreProcessInput事件的目的以及何時發生。 MSDN在這裏不是很有幫助。

+0

這段代碼對我很好,當鼠標仍然在`Window`上時`PreProcessInput`不會出現。如果您僅使用您發佈的代碼創建小型應用程序,您是否也能獲得相同的效果?你使用哪個.NET版本? – 2011-02-10 23:12:54

+0

@Meleak:謝謝!事實上,它只與上面的代碼一起工作(對我來說是恥辱)。無論如何,在我的項目中,我仍然有這種奇怪的行爲。我正在研究和縮小這一點,並提供更詳細的信息。爲了完整起見,我使用的是.NET 4. – 2011-02-11 09:43:33

+0

@Meleak:我已經更新了這個問題,這樣的行爲實際上是可以理解的。 – 2011-02-11 11:31:34

回答

15

我可以弄清楚是什麼導致了所描述的行爲。

例如,當一個控制的Visibility改變時,PreProcessInput事件引發與類型InputReportEventArgsPreProcessInputEventArgs.StagingItem.Input

行爲可以通過過濾InputEventArgs爲類型MouseEventArgsKeyboardEventArgsOnActivity事件,並且如果沒有按下鼠標按鈕,光標的位置仍然是相同的應用程序變爲非激活,以驗證被避免。

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(); 
     } 
    } 
} 
36

我們已經爲我們的軟件同樣需要...這是一個WPF應用程序,以及,作爲安全功能 - 客戶可以配置,如果他們有空閒的用戶將被註銷的時間。

下面是我提出來包裝空閒檢測代碼(利用內置在Windows功能)的類。

我們只是有一個計時器滴答曾經1秒檢查空閒時間比規定的閾值...取0 CPU。

首先,這裏是如何使用代碼:

var idleTime = IdleTimeDetector.GetIdleTimeInfo(); 

if (idleTime.IdleTime.TotalMinutes >= 5) 
{ 
    // They are idle! 
} 

您可以使用此,也確保您的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; 
    } 
} 
0

我在IdleDetector類中實現瞭解決方案。我改進了一些代碼。 Iddle探測器會拋出一個IsIdle,它可以被攔截!它給了!我等待一些評論。

public class IdleDetector 
{ 
    private readonly DispatcherTimer _activityTimer; 
    private Point _inactiveMousePosition = new Point(0, 0); 

    private IInputElement _inputElement; 
    private int _idleTime = 300; 

    public event EventHandler IsIdle; 

    public IdleDetector(IInputElement inputElement, int idleTime) 
    { 
     _inputElement = inputElement; 
     InputManager.Current.PreProcessInput += OnActivity; 
     _activityTimer = new DispatcherTimer { Interval = TimeSpan.FromSeconds(idleTime), IsEnabled = true }; 
     _activityTimer.Tick += OnInactivity; 
    } 

    public void ChangeIdleTime(int newIdleTime) 
    { 
     _idleTime = newIdleTime; 

     _activityTimer.Stop(); 
     _activityTimer.Interval = TimeSpan.FromSeconds(newIdleTime); 
     _activityTimer.Start(); 
    } 

    void OnInactivity(object sender, EventArgs e) 
    { 
     _inactiveMousePosition = Mouse.GetPosition(_inputElement); 
     _activityTimer.Stop(); 
     IsIdle?.Invoke(this, new EventArgs()); 
    } 

    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(_inputElement)) 
        return; 
      } 

      _activityTimer.Stop(); 
      _activityTimer.Start(); 
     } 
    } 
}