wpf f1 help не работает для всех пользовательских элементов управления

Я пишу приложение wpf и пытаюсь добавить в него поддержку справки F1.

Я нашел этот очень полезный класс Найджела Шоу

Я написал тестовый файл справки chm для Microsoft HTML Help Workshop.

Я интегрировал их в свое приложение. Я установил HelpTopic для своего главного окна, пользовательский элемент управления (CC1), который я динамически добавляю в главное окно, и другой пользовательский элемент управления (CC2), который я динамически добавляю в CC1.

Когда я нажимаю клавишу F1 в главном окне, я получаю правильную подсказку для открытия. Когда я нажимаю F1 в CC1, я получаю правильную подсказку для открытия. Когда я нажимаю F1 в CC2, я получаю предмет справки 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, GotFocus правильно запускается FocusManager из AnimatedStructure_MouseLeftButtonDown НО, сразу после этого я получаю LostFocus от самого CC2. Я посмотрел на RoutedEventArgs, и это действительно CC2, который удаляет свой собственный фокус.

Так что теперь я немного растерялся, что делать... Из-за этого я не могу

1 ответ

Решение

Наконец-то нашли проблему и решение в одной простой записи в блоге

Спасибо, кто вы, кто написал эту запись в блоге.

Краткий ответ: механизм WPF Focus сильно сломан.

Для длинного ответа просто прочитайте блог, поскольку автор дает подробности о том, почему поведение, которое я испытал, происходит.

Я добавил следующий класс к своему решению

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

Ура!

Другие вопросы по тегам