WPF: время простоя приложения - PullRequest
10 голосов
/ 20 июля 2010

Мне нужно сосчитать время простоя моего приложения WPF (Время простоя = когда не было ввода с клавиатуры, произошел ввод с помощью мыши (движение + щелчки)).До сих пор я пробовал 2 подхода, но ни один из них, похоже, не работает:

  1. При использовании диспетчера для вызова делегата каждый раз, когда он получает приоритет contextIdle, проблема заключается в том, что связывание и многие другие операции вызывают егои, таким образом, я не могу использовать это.
  2. с помощью диспетчера ввода, который я зарегистрировал для события «System.Windows.Input.InputManager.Current.PostProcessInput», и каждый раз, когда он вызывался, я перезапускал счетчик времени простоя,Второй подход казался многообещающим, но проблема в том, что когда мышь находится над приложением (оно имеет фокус), я продолжаю получать событие.

Есть ли другие идеи?или, может быть, способ изменить 2-е решение для работы?

Ответы [ 2 ]

13 голосов
/ 15 апреля 2011

Я решил проблему, используя несколько различных техник, чтобы дать мне довольно хорошее решение.Я использую GetLastInput, чтобы работать, когда система в последний раз была затронута. Это хорошо документировано в другом месте, но вот мой метод:

public static class User32Interop
{
    public static TimeSpan GetLastInput() 
    { 
        var plii = new LASTINPUTINFO();
        plii.cbSize = (uint)Marshal.SizeOf(plii); 
        if (GetLastInputInfo(ref plii))       
            return TimeSpan.FromMilliseconds(Environment.TickCount - plii.dwTime); 
        else       
            throw new System.ComponentModel.Win32Exception(Marshal.GetLastWin32Error()); 
    }

    [DllImport("user32.dll", SetLastError = true)]
    static extern bool GetLastInputInfo(ref LASTINPUTINFO plii);
    struct LASTINPUTINFO { 
        public uint cbSize; 
        public uint dwTime;   
    }
}

Это говорит только о том, что система бездействует, а не приложение.Если пользователь нажимает на Word и работает там в течение часа, я все еще хочу тайм-аут.Чтобы справиться с этим случаем, я просто помню, как мое приложение теряет фокус, переопределяя методы OnDeactivation и OnActivation для объекта приложения:

    override protected void OnDeactivated(EventArgs e)
    {
        this._lostFocusTime = DateTime.Now;
        base.OnDeactivated(e);
    }

    protected override void OnActivated(EventArgs e)
    {
        this._lostFocusTime = null;
        base.OnActivated(e);
    }

Моя подпрограмма IsIdle была добавлена ​​в объект приложения.Он обрабатывает глобальный случай, когда приложение имеет фокус, но ничего не произошло (IsMachineIdle) и конкретный случай, когда приложение теряет фокус, пока пользователь выполняет другие действия (isAppIdle):

    public bool IsIdle
    {
        get
        {
            TimeSpan activityThreshold = TimeSpan.FromMinutes(1);
            TimeSpan machineIdle = Support.User32Interop.GetLastInput();
            TimeSpan? appIdle = this._lostFocusTime == null ? null : (TimeSpan?)DateTime.Now.Subtract(_lostFocusTime.Value);
            bool isMachineIdle = machineIdle > activityThreshold ;
            bool isAppIdle = appIdle != null && appIdle > activityThreshold ;
            return isMachineIdle || isAppIdle;
        }
    }

Последнее, что я сделалбыло создать цикл таймера, который опрашивал это событие флага несколько секунд.

Кажется, это работает нормально.

5 голосов
/ 23 июля 2010

Ну, похоже, никто не ответил, поэтому я продолжил копать и нашел относительно простое решение, использующее время последнего ввода ОС + время. код действительно прост, но это решение заставляет меня проводить опрос данных, который я никогда не рекомендую, и вместо того, чтобы находиться на уровне приложения, он находится на уровне ОС, что не является точным решением, в котором я нуждался. Если кто-нибудь когда-нибудь откроет эту ветку, это код, просто используйте GetIdleTime ():

 public class IdleTimeService
{
    //Importing the Dll & declaring the necessary function
    [DllImport("user32.dll")]
    private static extern bool GetLastInputInfo(ref LASTINPUTINFO plii);


    /// <summary>
    /// return the current idle time (in ms)
    /// </summary>
    /// <returns>current idle time in ms</returns>
    public static int GetIdleTime()
    {

        //Creating the object of the structure
        LASTINPUTINFO lastone = new LASTINPUTINFO();

        //Initialising  
        lastone.cbSize = (uint)Marshal.SizeOf(lastone);
        lastone.dwTime = 0;

        int idleTime = 0;

        //To get the total time after starting the system.
        int tickCount = System.Environment.TickCount;

        //Calling the dll function and getting the last input time.
        if (GetLastInputInfo(ref lastone))
        {
            idleTime = tickCount - (int)lastone.dwTime;
            return idleTime;
        }
        else
            return 0;
    }


}
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...