Элементы управления, такие как TreeViewItems, должны иметь фокус для получения событий клавиатуры.
У вас есть несколько вариантов здесь.Вы можете поместить событие в само TreeView, но это работает, только если у дерева есть фокус клавиатуры.Пока это единственный элемент управления в окне, ты в порядке.Если это не так, у вас проблемы, и вам нужно обработать ключевое событие на уровне окна.Другой вариант заключается в том, чтобы написать триггер в вашем ItemContainerStyle, который дает фокус на клавиатуре древовидных представлений при IsMouseOver.Но это глупо.
Давайте сделаем это на уровне окна, потому что мы можем обобщить его: где бы вы ни нажимали F1 в этом окне, мы будем искать элемент управления под мышью и его родителями для элемента, который имеет DataContext с HelpId
имущество.Если мы найдем один, мы будем использовать его.Если ReportType
является единственным классом vm, который имеет HelpId, он будет работать нормально.Если вы добавите HelpId в другой класс, это будет работать.Если вы решите также включить ReportTypes в ListView, это будет работать.
Это заменяет весь код в вашем вопросе.
MainWindow.xaml
...
PreviewKeyDown="Window_PreviewKeyDown"
...
MainWindow.xaml.cs
private void Window_PreviewKeyDown(object sender, KeyEventArgs e)
{
if (e.Key == Key.F1)
{
var window = sender as Window;
var point = Mouse.GetPosition(window);
Helpers.ExecuteHelpUnderPoint(window, point);
}
}
Helpers.cs
public static class Helpers
{
public static void ExecuteHelpUnderPoint(FrameworkElement parent, Point point)
{
var hittestctl = parent.InputHitTest(point) as FrameworkElement;
var helpID = GetNearestDataContextHelpID(hittestctl);
if (helpID != null)
{
ApplicationCommands.Help.Execute(helpID, hittestctl);
}
}
public static IEnumerable<T> GetAncestorsOfType<T>(DependencyObject dobj) where T : DependencyObject
{
dobj = VisualTreeHelper.GetParent(dobj);
while (dobj != null)
{
if (dobj is T t)
yield return t;
dobj = VisualTreeHelper.GetParent(dobj);
}
}
public static Object GetNearestDataContextHelpID(DependencyObject dobj)
{
var dataContexts = GetAncestorsOfType<FrameworkElement>(dobj)
.Select(fe => fe.DataContext).Where(dc => dc != null);
// LINQ distinct probably doesn't affect order, but that's not guaranteed.
// https://stackoverflow.com/a/4734876/424129
object prev = null;
foreach (var dc in dataContexts)
{
if (dc != prev)
{
var prop = dc.GetType().GetProperty("HelpId");
if (prop != null)
{
var value = prop.GetValue(dc);
if (value != null)
{
return value;
}
}
prev = dc;
}
}
return null;
}
}