Excel 带有 WebBrowser 控件的 CustomTaskPane - keyboard/focus 个问题

Excel CustomTaskPane with WebBrowser control - keyboard/focus issues

我遇到了这个问题 https://social.msdn.microsoft.com/Forums/vstudio/en-US/e417e686-032c-4324-b778-fef66c7687cd/excel-customtaskpane-with-webbrowser-control-keyboardfocus-issues?forum=vsto

这里也提到了https://connect.microsoft.com/VisualStudio/feedback/details/521465/the-focus-issue-between-excel-cells-and-excel-customtaskpane-with-webbrowser-control

我正在使用 Visual Studio Professional 2013 编写一个 Excel 2010 插件。我创建了一个带有 System.Windows.Forms.WebBrowser child 归档的简单 CustomTaskPane。该插件工作正常,我可以通过单击并更改复选框的状态在网络浏览器中导航。

当我点击一个输入文本框时,我获得了焦点并且我看到光标闪烁,但是当我开始输入时,文本被发送到 Excel 并写入一个单元格而不是浏览器内的文本框。

我在加载功能区时添加了自定义任务窗格。

private void Ribbon_Load(object sender, RibbonUIEventArgs e)
{
  TaskPaneView taskPaneView = new TaskPaneView();
  Microsoft.Office.Tools.CustomTaskPane myTaskPane = Globals.ThisAddIn.CustomTaskPanes.Add(taskPaneView, "Title");
  myTaskPane.Visible = true;
}

当我点击文本框然后点击 F6 它工作正常。自定义任务窗格 header 稍微变暗,文本被捕获到文本框中。

我该如何解决这个问题,以便当我单击输入文本框时,文本会进入文本框而不是 Excel?

编辑:好的,我做了更多测试。 如果我在我的 TaskPaneView 上添加事件以跟踪鼠标输入和单击它们工作,但前提是我删除网络浏览器 child.这意味着网络浏览器以某种方式阻止了这些事件并阻止 TaskPaneView 理解它具有焦点。如果我还在浏览器旁边的 TaskPaneView 中添加了一个文本框表单控件,则文本框工作得很好,TaskPaneView 知道它有焦点,然后浏览器内的输入文本字段开始工作。如果我直接在网络浏览器上调用 focus 方法,TaskPaneView 就会知道它有焦点并且一切正常。很明显,问题不在于键盘,而是在单击浏览器时没有告知 TaskPaneView 它具有焦点的问题,因此击键会转到错误的区域。如果我能找到一种方法让 TaskPaneView 理解它具有焦点,那么一切都应该有效。

好的,我能够使用以下代码解决问题

protected override void WndProc(ref Message m)
{
  const int WM_PARENTNOTIFY = 528;
  if(m.Msg == WM_PARENTNOTIFY && !this.Focused)
  {
    this.Focus();
  }
  base.WndProc(ref m);
}

我将此功能添加到我的 TaskPaneView 中,它只是一个带有该网络浏览器子项的 UserControl。我对它为什么或如何工作没有深刻的理解,但基本上我认为发生的事情是我正在拦截 WndProc,它是一些处理发送到 window 的消息的低级函数。我用它来检查消息是否为 528,我认为这意味着 notifyParent。我不知道这是否正是我应该收听的消息,但它似乎有效。

收到正确的消息消息后,我会检查 TaskPaneView 是否有焦点,如果没有,我会使用 focus() 函数为其提供焦点。我之前做过测试,结果表明如果我在 TaskPaneView 上手动调用 focus 一切正常。所以如果我没有焦点,然后手动请求焦点,我们都很好。

如果有人能提供更详细的解释,说明为什么会这样,以便我更好地理解,我将不胜感激,但至少我解决了问题。感谢 Jeremy Thompson 让我以新的方式思考这个问题。

问:请提供更详细的解释,说明为什么会这样,以便我更好地理解它

很高兴你成功了!要执行根本原因分析,我们需要查看 528 消息的发送位置,并且我们需要 Microsoft Excel 源代码来执行此操作。

I don't think its worth spending anymore time troubleshooting it or working out why it happens because IT IS A BUG! Logging a Connect bug to help Microsoft fix it is the best thing you can do. We can only work around it, it's a problem in their source code.

您很少会在 VSTO 中发现这些场景的错误,而您肯定已经找到了;用户在加载项文本框中输入文本,消息流入工作表中的单元格!!在我的情况下;消息未发送到 Calendars_SelectedChange() 事件的位置。因此,我们可以看到 Hans 很好地解释了这里形成的行为主题 (引用我在评论中链接的问答)

What's never not a problem (ie can often be problematic) is that you rely on the message pump in Excel to dispatch Windows messages, the messages that make these controls respond to input. This goes wrong in WPF as much as Winforms, they have their own dispatch loop that filters messages before they are delivered to the window. Key things that go wrong when their respective dispatcher isn't used are stuff like tabbing and short-cut keystrokes.

And then some, this kind of problem would be induced by Excel doing its own filtering before dispatching messages. I'd guess at an anti-malware feature, Microsoft is forever worried about programs messing with Office apps.

并且不要忘记 VSTO WPF Connect case with menu's not receiving click events。解决方法涉及使用 DispatcherFrame 来发送消息并为菜单订阅 GotFocusEvent 和 LostFocusEvent

所以这个错误与响应输入的控件有关,void WndProc(ref Message m) 消息在调度循环中被错误地过滤或重定向。