我有一个用户控件,它接受输入手势来执行各种命令。在下面的示例图中,用户可以按 Ctrl + N 执行New
命令以在TreeView
中创建新项目。
当此用户控件托管在WPF应用程序中时,当焦点位于TreeView
时,用户可以使用 Ctrl + N 创建新项目kbd> Ctrl + N 当焦点位于应用程序的其他位置时,将执行应用程序级New
命令。
当此用户控件托管在VSPackage ToolWindow中时,当用户按下 Ctrl + N 时,将执行用于创建新文件的VS Shell级别New
命令,而不管是否关注TreeView
。
如何防止VS Shell获得密钥/命令绑定的优先级?
答案 0 :(得分:0)
主持人Ryan在MSDN上提出了一些方法。 VS Shell将Winform消息传递给ToolWindow,因此当前的方法是覆盖ToolWindow中的PreProcessMessage,处理将映射到WPF命令的 Ctrl + N 等组合键,然后翻译这些组合。消息并传递给ComponentDispatcher.RaiseThreadMessage。
这种方法容易出错,因为到WPF命令的映射可能会失去同步,而且它不会包含WPF命令是否可以执行。如果有人有更理想的方法,请告诉我,如果我找到,将发布。
也许WPF控件有一种方法可以传回命令是否已执行,然后只有在执行命令时才会处理消息。然后,可以避免所有这些映射业务。
private bool isControlKeyDepressed = false;
private bool isShifKeyDepressed = false;
private bool isOtherKeyDepressed = false;
private bool isCommandCombinationDepressed = false;
protected override bool PreProcessMessage(ref Message msg)
{
// trap keyboard messages if window has focus
if (msg.Msg == 256)
{
if (msg.WParam == (IntPtr)17)
{
isControlKeyDepressed = true;
isOtherKeyDepressed = false;
}
else if (msg.WParam == (IntPtr)16)
{
isShifKeyDepressed = true;
isOtherKeyDepressed = false;
}
else
{
if (isOtherKeyDepressed == true)
{
isControlKeyDepressed = false;
isShifKeyDepressed = false;
}
isOtherKeyDepressed = true;
if (isControlKeyDepressed == true)
{
if (isShifKeyDepressed == true)
{
switch (msg.WParam.ToInt64())
{
case 65: // Ctrl+Shift+A command
case 67: // Ctrl+Shift+C command
case 78: // Ctrl+Shift+N command
case 79: // Ctrl+Shift+O command
case 83: // Ctrl+Shift+S command
case 85: // Ctrl+Shift+U command
case 88: // Ctrl+Shift+X command
isCommandCombinationDepressed = true;
break;
default:
isCommandCombinationDepressed = false;
break;
}
}
else
{
switch (msg.WParam.ToInt64())
{
case 69: // Ctrl+E command
case 78: // Ctrl+N command
case 79: // Ctrl+O command
case 83: // Ctrl+S command
isCommandCombinationDepressed = true;
break;
default:
isCommandCombinationDepressed = false;
break;
}
}
}
else
{
isCommandCombinationDepressed = false;
}
}
if (isCommandCombinationDepressed == true)
{
// send translated message via component dispatcher
MSG dispatchMsg = new MSG();
dispatchMsg.hwnd = msg.HWnd;
dispatchMsg.lParam = msg.LParam;
dispatchMsg.wParam = msg.WParam;
dispatchMsg.message = msg.Msg;
ComponentDispatcher.RaiseThreadMessage(ref dispatchMsg);
msg.Result = (IntPtr)1;
return true;
}
}
return base.PreProcessMessage(ref msg);
}