要在WPF窗口中使用加速键,必须使用Label
控件。指定控件以将焦点放在其Target
属性中,并在热键前加_
前缀。这适用于TextBox
控件,但不适用于ListBox
。而不是专注于"聚焦" item,列表框控件本身是重点。按箭头键然后做不可预测的事情。像这样完全无法使用。显然这个问题现在存在for ten years。
以下是一些演示代码:
<Label Content="_List:" Target="{Binding ElementName=myList}"/>
<ListBox Name="myList" Items="..."/>
<Button Content="OK"/>
您需要先在列表中放入一些项目,然后选择第二项。单击按钮仅对焦。然后按 Alt + L 以聚焦列表。
我是否应该开始讨论ListBox
的{{1}}事件以确定焦点?或者有适当的解决方案吗?我是否想念一些充满异国情调的房产才能使它成为现实?
答案 0 :(得分:0)
我找到了解决这个问题的方法。它不涉及任何每个控件的自定义。所有必要的事件都会根据默认样式自动附加到所有ListBox
控件。
我正在处理所有GotKeyboardFocus
控件的ListBox
事件,以检查焦点是否真正属于除ListBox
之外的其他人。如果选择了某个项目,它将被聚焦。如果没有,并且列表中至少有一个项目,则第一个项目将被聚焦。这也会隐含地选择它(这是错误的),所以这也是固定的。
这不是本机Windows行为的精确复制,因为当焦点位于另一个控件上时,它不会保留焦点项。 Windows窗体“ListBox
区分一个或多个所选项目和一个焦点项目。每个都被正确跟踪和记住。 WPF的ListBox
似乎并不关心项目焦点(显然,或者这整个悲伤的解决方案都没有必要),因此必须做出假设。
这在我的应用程序中运行良好,不会从用户的角度来惹恼我。在两个方向上切换控件都可以顺利运行。
附加属性在ListBoxExtensions
类(ListBoxExtensions.cs
)中实现:
using System;
using System.Reflection;
using System.Windows;
using System.Windows.Controls;
using System.Windows.Input;
namespace Unclassified.UI
{
/// <summary>
/// Provides extension methods for WPF ListBox controls.
/// </summary>
// Type name used in XAML
[Obfuscation(Exclude = true, ApplyToMembers = false, Feature = "renaming")]
public static class ListBoxExtensions
{
#region ListBox fix focus attached property
/// <summary>
/// Identifies the FixFocus XAML attached property.
/// </summary>
public static readonly DependencyProperty FixFocusProperty = DependencyProperty.RegisterAttached(
name: "FixFocus",
propertyType: typeof(bool),
ownerType: typeof(ListBoxExtensions),
defaultMetadata: new PropertyMetadata(OnFixFocusChanged));
/// <summary>
/// Gets the value of the FixFocus XAML attached property from the specified DependencyObject.
/// </summary>
/// <param name="obj">The object from which to read the property value.</param>
/// <returns></returns>
public static bool GetFixFocus(DependencyObject obj)
{
return (bool)obj.GetValue(FixFocusProperty);
}
/// <summary>
/// Sets the value of the FixFocus XAML attached property on the specified DependencyObject.
/// </summary>
/// <param name="obj">The target object on which to set the FixFocus XAML attached property.</param>
/// <param name="value">The property value to set.</param>
public static void SetFixFocus(DependencyObject obj, bool value)
{
obj.SetValue(FixFocusProperty, value);
}
private static void OnFixFocusChanged(DependencyObject obj, DependencyPropertyChangedEventArgs args)
{
if (obj is ListBox && args != null)
{
if ((bool)args.NewValue)
{
((ListBox)obj).GotKeyboardFocus += ListBox_GotKeyboardFocus;
}
else
{
((ListBox)obj).GotKeyboardFocus -= ListBox_GotKeyboardFocus;
}
}
}
private static void ListBox_GotKeyboardFocus(object sender, KeyboardFocusChangedEventArgs args)
{
var listBox = sender as ListBox;
if (listBox?.IsKeyboardFocused == true)
{
// ListBox has KeyboardFocus, it really should be on an item instead to fix keyboard navigation
if (listBox.SelectedItem != null)
{
// Focus the selected item
(listBox.ItemContainerGenerator.ContainerFromItem(listBox.SelectedItem) as UIElement)?.Focus();
}
else if (listBox.Items.Count > 0)
{
// Focus the first item. This implicitly selects it. Clear selection afterwards.
(listBox.ItemContainerGenerator.ContainerFromIndex(0) as UIElement)?.Focus();
listBox.SelectedItem = null;
}
}
}
#endregion ListBox fix focus attached property
}
}
将此添加到ResourceDictionary
引用的App.xaml
:
<ResourceDictionary
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:ui="clr-namespace:Unclassified.UI"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml">
<Style TargetType="ListBox" BasedOn="{StaticResource {x:Type ListBox}}">
<Setter Property="ui:ListBoxExtensions.FixFocus" Value="True"/>
</Style>
</ResourceDictionary>