0

我正在编写一个 wpf 应用程序,并尝试为其添加 F1 帮助支持。

我发现Nigel Shaw 的这个非常有用的课程

我使用 Microsoft HTML Help Workshop 编写了一个测试帮助 chm 文件。

我将它们集成到我的应用程序中。我为我的主窗口设置了 HelpTopic,一个自定义控件 (CC1) 我动态添加到主窗口,另一个自定义控件 (CC2) 我动态添加到 CC1。

当我在主窗口中按 F1 时,我会打开正确的帮助主题。当我在 CC1 中按 F1 时,我会得到正确的帮助主题以打开。当我在 CC2 中按 F1 时,我得到 CC1 的帮助主题。

当调用 GetHelpTopic 函数时,我添加了一些代码来获取控件堆栈,这就是我得到的([0] 是捕获 F1 的控件):

[0] System.Windows.Controls.ScrollViewer
[1] System.Windows.Controls.Grid
[2] System.Windows.Controls.Grid
[3] System.Windows.Controls.Grid
[4] CC1
[5] System.Windows.Controls.Canvas
[6] System.Windows.Controls.ScrollViewer
[7] System.Windows.Controls.Grid
[8] System.Windows.Controls.Grid
[9] CustomPanel
[10] System.Windows.Controls.TabItem
[11] System.Windows.Controls.TabControl
[12] System.Windows.Controls.Grid
[13] MainWindow

起初我认为可能是 ScrollViewer 抓住了 F1 并阻止它深入。但是我会从 [6] 开始获得堆栈。

然后我认为问题可能来自CC1和CC2类之间的差异。但它们都继承自同一个基类,后者继承自 UserControl

UserControl - UserControlXY - AnimatedControl - AnimatedControlValidated - CC1

UserControl - UserControlXY - AnimatedControl - AnimatedControlValidated - AnimatedStructure - CC2

更新1:我越来越近了。如果我在 CC2 中的控件内单击,则会得到以下堆栈

[0] System.Windows.Controls.TextBox
[1] System.Windows.Controls.Grid
[2] System.Windows.Controls.Grid
[3] CC2
[4] System.Windows.Controls.Canvas
[5] System.Windows.Controls.ScrollViewer
[6] System.Windows.Controls.Grid
[7] System.Windows.Controls.Grid
[8] System.Windows.Controls.Grid
[9] CC1
[10] System.Windows.Controls.Canvas
[11] System.Windows.Controls.ScrollViewer
[12] System.Windows.Controls.Grid
[13] System.Windows.Controls.Grid
[14] CustomPanel
[15] System.Windows.Controls.TabItem
[16] System.Windows.Controls.TabControl
[17] System.Windows.Controls.Grid
[18] MainWindow

我得到了 CC2 的正确帮助主题。所以我猜这是当我点击它时将焦点设置在CC2上的问题。

所以我在 CC2 中添加了以下标签:

Focusable="True"

但在那种情况下,当我单击 CC2 背景或不可聚焦的元素(例如:标签)时,我仍然会得到以前的错误行为......

所以接下来我添加了一个 MouseLeftButtonDown 来手动设置焦点

MouseLeftButtonDown += new System.Windows.Input.MouseButtonEventHandler(AnimatedStructure_MouseLeftButtonDown);

随着事件这样做:

private void AnimatedStructure_MouseLeftButtonDown(object sender, System.Windows.Input.MouseButtonEventArgs e)
{
   this.Focus();
}

但即使这样,我仍然得到以前错误的帮助主题......


更新 2:

这次我添加到CC2

GotFocus += new System.Windows.RoutedEventHandler(AnimatedStructure_GotFocus);
LostFocus += new System.Windows.RoutedEventHandler(AnimatedStructure_LostFocus);

我还修改了 AnimatedStructure_MouseLeftButtonDown 以像这样使用 FocusManager:

FocusManager.SetFocusedElement(this.Parent, this);

我在 GotFocus 和 LostFocus 中设置了一个断点。当我在 CC2 内部单击时,FocusManager 从 AnimatedStructure_MouseLeftButtonDown BUT 正确触发 GotFocus,之后我立即从 CC2 本身收到一个 LostFocus。我查看了 RoutedEventArgs,它确实是 CC2 本身消除了它自己的焦点。

所以现在我对该怎么做有点迷茫......因此我不能

4

1 回答 1

0

终于在一篇简单的博文中找到了问题和解决方案

谢谢你是谁写了那个博客条目。

简短的回答:WPF 焦点机制被严重破坏。

对于长答案,只需阅读博客,因为作者详细说明了我所经历的行为发生的原因。

我在我的解决方案中添加了以下类

static class FocusHelper
{
    private delegate void MethodInvoker();

    public static void Focus(UIElement element)
    {
        //Focus in a callback to run on another thread, ensuring the main UI thread is initialized by the
        //time focus is set
        ThreadPool.QueueUserWorkItem(delegate(Object foo) {
            UIElement elem = (UIElement)foo;
            elem.Dispatcher.Invoke(System.Windows.Threading.DispatcherPriority.Normal,
                (MethodInvoker)delegate()
            {
                elem.Focus();
                Keyboard.Focus(elem);
            });
        }, element);
    }
}

而这在 CC2

MouseLeftButtonDown += new System.Windows.Input.MouseButtonEventHandler(AnimatedStructure_MouseLeftButtonDown);

private void AnimatedStructure_MouseLeftButtonDown(object sender, System.Windows.Input.MouseButtonEventArgs e)
{
    FocusHelper.Focus(this);
}

那成功了。现在焦点已正确设置并保持在 CC2 上,我得到了正确的 HelpTopic

欢呼!

于 2013-12-11T14:08:56.300 回答