Команда Visual Studio обладает хорошей информацией об уроках, которые они извлекли при создании VS в WPF.Одна из проблем, с которыми они столкнулись, была связана с управлением фокусом.В результате в WPF 4 появилось несколько новых функций, которые могут помочь.
Вот информация по проблеме, которая звучит как ваша ситуация:
http://blogs.msdn.com/b/visualstudio/archive/2010/03/09/wpf-in-visual-studio-2010-part-3-focus-and-activation.aspx
Их обсуждениеновое свойство "HwndSource.DefaultAcquireHwndFocusInMenuMode" звучит очень похоже на то, с чем вы сталкиваетесь.
EDIT
После дальнейшего исследования кажется, что Visual Studio может подключатьсяцикл сообщений Windows и возвращение определенных значений, чтобы заставить работать плавающие окна.
Я не программист на win32, но кажется, что когда пользователь щелкает меню в неактивном окне, Windows отправляет ему сообщение WM_MOUSEACTIVATE перед обработкой события мыши.Это позволяет главному окну определить, следует ли его активировать.
В моем неизмененном тестовом приложении WPF неактивное окно возвращает MA_ACTIVATE .Однако VS возвращает MA_NOACTIVATE .Документы указывают, что это говорит окнам НЕ активировать главное окно перед обработкой дальнейшего ввода.Я предполагаю, что Visual Studio перехватывает цикл сообщений Windows и возвращает MA_NOACTIVATE , когда пользователь нажимает на меню / панели инструментов.
Я смог сделать эту работу в простом, два окнаПриложение WPF, добавив этот код в окно верхнего уровня.
protected override void OnSourceInitialized(EventArgs e)
{
base.OnSourceInitialized(e);
var hook = new HwndSourceHook(this.FilterMessage);
var source2 = HwndSource.FromVisual(this) as HwndSource;
source2.AddHook(hook);
}
private IntPtr FilterMessage(IntPtr hwnd, int msg, IntPtr wParam, IntPtr lParam, ref bool handled)
{
const int WM_MOUSEACTIVATE = 0x0021;
const int MA_NOACTIVATE = 3;
switch (msg)
{
case WM_MOUSEACTIVATE:
handled = true;
return new IntPtr(MA_NOACTIVATE);
}
return IntPtr.Zero;
}
В вашем случае вам, вероятно, потребуется добавить дополнительную логику, которая будет проверять, что пользователь нажал, и на основе этого решать, следует ли перехватыватьсообщение и возврат MA_NOACTIVATE.
РЕДАКТИРОВАТЬ 2
Я приложил образец WPF-приложения , который показывает, как это сделать с помощью простого WPFприложение.Это должно работать почти так же, как с плавающими окнами из набора инструментов для стыковки, но я не тестировал этот конкретный сценарий.
Образец доступен по адресу: http://blog.alner.net/downloads/floatingWindowTest.zip
В примере есть комментарии к коду, чтобы объяснить, как это работает.Чтобы увидеть его в действии, запустите образец, нажмите кнопку «открыть другое окно».Это должно поместить фокус в текстовое поле нового окна.Теперь нажмите меню редактирования в главном окне и используйте команды, такие как «выбрать все».Они должны работать в другом окне, не выводя «главное окно» на передний план.
Вы также можете нажать на пункт меню «выход», чтобы увидеть, что он все еще может направлять команды в главное окно, если это необходимо.
Ключевые точки (активация / фокус):
- Используйте HwndSource.DefaultAcquireHwndFocusInMenuMode, чтобы заставить работать меню, прекратить захват фокуса.
- Перехватить цикл сообщений и вернуться«MA_NOACTIVATE», когда пользователь щелкает меню.
- Добавьте обработчик событий в PreviewGotKeyboardFocus и установите для e.Handled значение true, чтобы меню не пыталось захватить фокус.
Ключевые точки (команды):
- Перехватывать события «CommandManager.PreviewCanExecute» и «CommandManager.PreviewExecuted» главного окна.
- В этих событиях определяется, имеет ли приложение «другое окно ", которое должно быть целью событий.
- Вручную вызвать исходную команду против" другого окна ".
Надеждаэто работает для вас.Если нет, дайте мне знать.