wpf f1有助于不适用于所有自定义控件

时间:2013-12-10 13:17:37

标签: wpf focus custom-controls chm lostfocus

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

我发现了very usefull class by Nigel Shaw

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

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

当我在主窗口中按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正确触发了GotFocus 但是,之后我立刻收到了CC2本身的LostFocus。 我查看了RoutedEventArgs,它真的是CC2本身,它消除了自己的焦点。

所以现在我有点迷失了怎么办...... 因为我不能

1 个答案:

答案 0 :(得分:0)

最后在一个simple blog entry

中找到了问题和解决方案

感谢您撰写该博客文章的人。

简短回答: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

乌拉!