Сохранить окно сверху и украсть фокус в WinForms
Я понимаю, что это будет ПОЛНОСТЬЮ плохой практикой в обычных ситуациях, но это только для тестового приложения, которое должно принимать входные данные от сканера штрих-кода (эмуляция клавиатуры). Проблема в том, что мне нужно запускать некоторые скрипты во время сканирования, поэтому мне нужно окно, чтобы восстановить фокус непосредственно после того, как я нажму скрипт, чтобы запустить его. Я попытался использовать Активировать (), BringToFront (), Focus (), а также некоторые вызовы Win32, такие как SetForegroundWindow (), Setcapture () и SetActiveWindow () … однако лучшее, что я могу сделать, это сделать сделайте элемент панели задач мигающим, чтобы сказать мне, что он хочет сосредоточиться, но что-то останавливает его. BTW, я запускаю это на XP SP2 и с помощью .NET 2.0.
Это возможно?
Изменить. Чтобы уточнить, я запускаю скрипты, дважды щелкнув по ним в проводнике. Поэтому мне нужно, чтобы он украл фокус обратно из проводника и в тестовое приложение.
- Как определить событие EventGridView CheckBox?
- Событие, зарегистрированное в CheckedListBox?
- Отображение всплывающей подсказки по кнопке с помощью Windows Forms
- C # Force Form Focus
- Как добавить событие в UserControl в C #?
- SendKeys.Send и ключ Windows
- Как найти элемент управления, который я добавил в форму?
- Как печатать значения из элемента управления DataGridView
- Максимальное количество символов, которое может отображать TextBox
- Слабые справочные преимущества
- Нарисуйте несколько рисунков полилинии или кривых свободной руки - добавление функции отмены
- Передача данных между двумя формами со свойствами
- Сохранить настройки в VB.Net или C #
видимость
Сделайте окно «самым большим». Так Менеджер задач может оставаться поверх других окон. Это свойство Form
и вы делаете форму самой верхней (плавающей над другими windowsми), устанавливая значение в true
.
Вам не нужно переопределять поведение «активного windows» с самой верхней настройкой.
фокус
Ранее я задал аналогичный вопрос в StackOverflow, и ответ решит вашу проблему. Вы можете заставить приложение использовать низкоуровневый входной крючок и получить уведомление о кодах клавиш, поступающих со сканера. Таким образом, ваше приложение всегда получает эти ключи, даже если приложение не имеет фокуса.
Возможно, вам нужно будет усилить решение для раздавливания кодов клавиш, чтобы они не передавались в приложение «в фокусе» (например, блокнот).
Начиная с Windows 2000, нет официального механизма приложения для захвата фокуса без прямого вмешательства пользователя. Подглядывание на входные streamи через крюк RawInputDevices – единственный разумный путь.
Ряд статей может помочь (реализация C #)
- Статья RawInput по CodeProject
- Документация MSDN для RawInput
Некоторое время я боролся с подобной проблемой. После долгих экспериментов и угадываний я решил это:
// Get the window to the front. this.TopMost = true; this.TopMost = false; // 'Steal' the focus. this.Activate();
У меня была аналогичная проблема, и я нашел следующее, чтобы сделать трюк. Адаптировано к C # отсюда
// force window to have focus uint foreThread = GetWindowThreadProcessId(GetForegroundWindow(), IntPtr.Zero); uint appThread = GetCurrentThreadId(); const uint SW_SHOW = 5; if (foreThread != appThread) { AttachThreadInput(foreThread, appThread, true); BringWindowToTop(form.Handle); ShowWindow(form.Handle, SW_SHOW); AttachThreadInput(foreThread, appThread, false); } else { BringWindowToTop(form.Handle); ShowWindow(form.Handle, SW_SHOW); } form.Activate();
EDIT: Вот необходимые определения PInvoke для C #:
[DllImport("user32.dll", SetLastError = true)] static extern uint GetWindowThreadProcessId(IntPtr hWnd, out uint lpdwProcessId); // When you don't want the ProcessId, use this overload and pass IntPtr.Zero for the second parameter [DllImport("user32.dll")] static extern uint GetWindowThreadProcessId(IntPtr hWnd, IntPtr ProcessId); [DllImport("kernel32.dll")] static extern uint GetCurrentThreadId(); /// The GetForegroundWindow function returns a handle to the foreground window. [DllImport("user32.dll")] private static extern IntPtr GetForegroundWindow(); [DllImport("user32.dll")] static extern bool AttachThreadInput(uint idAttach, uint idAttachTo, bool fAttach); [DllImport("user32.dll", SetLastError = true)] static extern bool BringWindowToTop(IntPtr hWnd); [DllImport("user32.dll", SetLastError = true)] static extern bool BringWindowToTop(HandleRef hWnd); [DllImport("user32.dll")] static extern bool ShowWindow(IntPtr hWnd, uint nCmdShow);
То, как я подошел к этой проблеме, состояло в том, чтобы создать еще один stream, единственная цель которого заключалась в том, чтобы форма была TopMost и всегда имела фокус. Этот код сделает все остальные приложения непригодными для использования во время работы, что я и нуждаюсь в своих конкретных приложениях. Вы можете добавить Sleep в режиме keepFocus или вызвать другое событие.
using System.Threading; // be sure to include the System.Threading namespace //Delegates for safe multi-threading. delegate void DelegateGetFocus(); private DelegateGetFocus m_getFocus; //Constructor. myForm() { m_getFocus = new DelegateGetFocus(this.getFocus); // initialise getFocus InitializeComponent(); spawnThread(keepFocus); // call spawnThread method } //Spawns a new Thread. private void spawnThread(ThreadStart ts) { try { Thread newThread = new Thread(ts); newThread.IsBackground = true; newThread.Start(); } catch(Exception e) { MessageBox.Show(e.Message, "Exception!", MessageBoxButtons.OK, MessageBoxIcon.Error); } } //Continuously call getFocus. private void keepFocus() { while(true) { getFocus(); } } //Keeps Form on top and gives focus. private void getFocus() { //If we need to invoke this call from another thread. if (this.InvokeRequired) { try { this.Invoke(m_getFocus, new object[] { }); } catch (System.ObjectDisposedException e) { // Window was destroyed. No problem but terminate application. Application.Exit(); } } //Otherwise, we're safe. else { this.TopMost = true; this.Activate(); } } }
вusing System.Threading; // be sure to include the System.Threading namespace //Delegates for safe multi-threading. delegate void DelegateGetFocus(); private DelegateGetFocus m_getFocus; //Constructor. myForm() { m_getFocus = new DelegateGetFocus(this.getFocus); // initialise getFocus InitializeComponent(); spawnThread(keepFocus); // call spawnThread method } //Spawns a new Thread. private void spawnThread(ThreadStart ts) { try { Thread newThread = new Thread(ts); newThread.IsBackground = true; newThread.Start(); } catch(Exception e) { MessageBox.Show(e.Message, "Exception!", MessageBoxButtons.OK, MessageBoxIcon.Error); } } //Continuously call getFocus. private void keepFocus() { while(true) { getFocus(); } } //Keeps Form on top and gives focus. private void getFocus() { //If we need to invoke this call from another thread. if (this.InvokeRequired) { try { this.Invoke(m_getFocus, new object[] { }); } catch (System.ObjectDisposedException e) { // Window was destroyed. No problem but terminate application. Application.Exit(); } } //Otherwise, we're safe. else { this.TopMost = true; this.Activate(); } } }
Вы можете попытаться сосредоточиться на определенном входе или попробовать установить свойство .TopMost в true (и затем снова отключить его).
Но я подозреваю, что ваша проблема заключается в том, что эти методы просто размещают сообщения в очереди событий Windows, и ваша программа должна дождаться завершения всех существующих событий до того, как она обработает этот, и сосредоточьте приложение.