Thread Dispatcher Sleep в WPF
Я пытаюсь создать приложение Kinect + WPF. Часть Kinect работает отлично; Теперь я хочу создать метод, чтобы проверить, простаивает ли страница (ни один пользователь не взаимодействует с программой в течение определенного периода времени). Если он не используется в течение 5 секунд, экран будет заблокирован. Это алгоритм:
- Начать поток (мне нужно использовать Dispatcher, поскольку поток должен изменять элементы WPF)
- Проверьте, использует ли пользователь. Если нет, то увеличьте счетчик на 1.
- Если счет == 9 (что означает, что прошло уже 5 секунд), заблокируйте экран и снова установите для счетчика значение 0.
- Спи 500 миллисекунд.
- Повторите шаг 2-4
Это мой код Метод startLockHandler вызывается при запуске приложения.
public void startLockHandler()
{
Application.Current.Dispatcher.BeginInvoke(new ThreadStart(() => lockHandler()), null);
}
public void lockHandler()
{
while (true)
{
if (myState.isSkeletonTracked == false) //if skeleton is no longer tracked
{
if (myState.ActionAllowed == true) //if the page is not in transition
{
lockCount++;
if (lockCount >= 10)
{
lockCount = 0;
myState.ActionAllowed = false;
//LOCKING MECHANISM INSERTED HERE. NEED TO MODIFY SOME WPF ELEMENTS
myState.ActionAllowed = true;
}
}
}
else
{
lockCount = 0;
}
Console.WriteLine("lockHandler: THREAD SLEEP CALLED");
Thread.Sleep ( 500 );
}//end while
}//end method lockHandler
Когда я запускаю приложение, оно зависает сразу после его запуска. Мне кажется, что Thread.Sleep (500) инструктирует основной поток спать (пожалуйста, исправьте меня, если я ошибаюсь). У меня вопрос, как я могу указать, какую нить нужно усыпить? Кстати, я не эксперт в C#, а новичок в Threading:(
Спасибо за ваше внимание и, надеюсь, вы можете помочь мне:)
1 ответ
Dispatcher.BeginInvoke()
не создает новый поток, он просто выполняет lockHandler() в основном потоке графического интерфейса. Тот факт, что вы проходитеThreadStart
делегат здесь ничего особенного не значит.Thread.Sleep()
помещает в спящий поток, который его вызвал, то есть основной поток GUI в вашем случае. Для управления выполнением одной команды из другой следует использовать примитивы синхронизации (ManualResetEvent
,AutoResetEvent
,Mutex
,Semaphore
, так далее).Вы не должны получать доступ к / изменять пользовательский интерфейс напрямую из другого потока, вы должны вызвать
Invoke
или жеBeginInvoke
Dispatcher
методы из вторичного потока (не потока GUI), чтобы гарантировать, что весь связанный с UI код выполняется из потока, который создал элементы UI.Вам действительно не нужен вторичный поток с выделенным
Dispatcher
экземпляр для вашего случая.
Минимальная модификация, в которой как минимум будет использоваться отдельный поток:
var thread = new Thread(lockHandler);
thread.Start();
Помните, что вам также необходимо реализовать способ остановки вторичного потока, иначе это может помешать вашему приложению закрываться и выгружаться из памяти. Quck и (очень) грязное решение будет пометить этот поток как фоновый поток: thread.IsBackground = true
,
Обновить
Пример изменения пользовательского интерфейса из вторичного потока:
Application.Current.Dispatcher.BeginInvoke(new Action(
() =>
{
// access UI elements here, for example
myState.ActionAllowed = false;
}));