我使用了大的答案从NathanAW创造了ResourceDictionary
含有Window
一个Style
(应由MainWindow
使用),包含在关键件来解决这个问题。
更新:为ToolBar
增加支持以及Menu
它包括命中测试专门为MainMenu的栏或工具栏,以决定是否重点应该被允许。
我之所以使用ResourceDictionary的理由是为了重复使用,因为我们将在很多项目中使用它。此外,MainWindow背后的代码可以保持清洁。
MainWindow
可以使用这个风格
<Window...>
<Window.Resources>
<ResourceDictionary>
<ResourceDictionary.MergedDictionaries>
<ResourceDictionary Source="NoFocusMenuWindowDictionary.xaml"/>
</ResourceDictionary.MergedDictionaries>
</ResourceDictionary>
</Window.Resources>
<Window.Style>
<StaticResource ResourceKey="NoFocusMenuWindow"/>
</Window.Style>
<!--...-->
</Window>
NoFocusMenuWindowDictionary.xaml
<ResourceDictionary xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
x:Class="MainWindowVS2010Mode.NoFocusMenuWindowDictionary">
<Style x:Key="NoFocusMenuWindow" TargetType="Window">
<EventSetter Event="Loaded" Handler="MainWindow_Loaded"/>
</Style>
<Style TargetType="Menu">
<EventSetter Event="PreviewGotKeyboardFocus"
Handler="Menu_PreviewGotKeyboardFocus"/>
</Style>
<Style TargetType="ToolBar">
<EventSetter Event="PreviewGotKeyboardFocus"
Handler="ToolBar_PreviewGotKeyboardFocus"/>
</Style>
</ResourceDictionary>
NoFocusMenuWindowDictionary.xaml.cs
namespace MainWindowVS2010Mode
{
public partial class NoFocusMenuWindowDictionary
{
#region Declaration
private static Window _mainWindow;
private static bool _mainMenuOrToolBarClicked;
#endregion // Declaration
void MainWindow_Loaded(object sender, RoutedEventArgs e)
{
_mainWindow = sender as Window;
HwndSource.DefaultAcquireHwndFocusInMenuMode = true;
Keyboard.DefaultRestoreFocusMode = RestoreFocusMode.None;
HwndSource hwndSource = HwndSource.FromVisual(_mainWindow) as HwndSource;
hwndSource.AddHook(FilterMessage);
}
private static 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:
if (ClickedMainMenuOrToolBarItem())
{
handled = true;
return new IntPtr(MA_NOACTIVATE);
}
break;
}
return IntPtr.Zero;
}
#region Hit Testing
private static bool ClickedMainMenuOrToolBarItem()
{
_mainMenuOrToolBarClicked = false;
Point clickedPoint = Mouse.GetPosition(_mainWindow);
VisualTreeHelper.HitTest(_mainWindow,
null,
new HitTestResultCallback(HitTestCallback),
new PointHitTestParameters(clickedPoint));
return _mainMenuOrToolBarClicked;
}
private static HitTestResultBehavior HitTestCallback(HitTestResult result)
{
DependencyObject visualHit = result.VisualHit;
Menu parentMenu = GetVisualParent<Menu>(visualHit);
if (parentMenu != null && parentMenu.IsMainMenu == true)
{
_mainMenuOrToolBarClicked = true;
return HitTestResultBehavior.Stop;
}
ToolBar parentToolBar = GetVisualParent<ToolBar>(visualHit);
if (parentToolBar != null)
{
_mainMenuOrToolBarClicked = true;
return HitTestResultBehavior.Stop;
}
return HitTestResultBehavior.Continue;
}
public static T GetVisualParent<T>(object childObject) where T : Visual
{
DependencyObject child = childObject as DependencyObject;
while ((child != null) && !(child is T))
{
child = VisualTreeHelper.GetParent(child);
}
return child as T;
}
#endregion // Hit Testing
#region Menu
private void Menu_PreviewGotKeyboardFocus(object sender, KeyboardFocusChangedEventArgs e)
{
Menu menu = sender as Menu;
if (menu.IsMainMenu == true)
{
e.Handled = true;
}
}
#endregion // Menu
#region ToolBar
private void ToolBar_PreviewGotKeyboardFocus(object sender, KeyboardFocusChangedEventArgs e)
{
e.Handled = true;
}
#endregion // ToolBar
}
}
感谢您的链接,我实际上已经阅读了三次。虽然不能真正使用这些属性来工作,但是,他们看起来好像是为了解决像这样的问题。有什么想法如何工作?:) –
Meleak,我添加了一些信息,我发现通过使用Spy ++来观看VS发送的Windows消息。通过将此代码添加到主窗口,我能够使一个简单的测试应用程序的行为与VS类似。主窗口有一个菜单控件,并且还打开了一个子窗口。通过上面的代码,点击菜单时,子窗口不会松动焦点。 – NathanAW
我已经创建了一个显示这个工作的示例。有几个比上面提到的更少的细节。这些在示例的代码注释中进行了描述。 – NathanAW