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
Ура!