标签没有正确聚焦列表框
Label doesn't properly focus a ListBox
为了在 WPF window 中使用快捷键,您必须使用 Label
控件。指定要在其 Target
属性 中聚焦的控件,并在热键前加上 _
。这适用于 TextBox
控件,但不适用于 ListBox
。焦点不是 "focused" 项,而是列表框控件本身。然后按箭头键会发生不可预测的事情。这样完全不能用。显然这个问题现在 for ten years 存在。
下面是一些演示代码:
<Label Content="_List:" Target="{Binding ElementName=myList}"/>
<ListBox Name="myList" Items="..."/>
<Button Content="OK"/>
您需要先将一些项目放入列表,然后 select 第二个。单击按钮仅将其聚焦。然后按 Alt+L 聚焦列表。
我应该开始搞乱 ListBox
的 GotFocus
事件来修复焦点吗?或者对此有适当的解决方案吗?我是否错过了一些异国情调 属性 来设置它?
我找到了解决这个问题的方法。它不涉及任何 per-control 定制。根据默认样式,所有必要的事件都会自动附加到所有 ListBox
控件。
我正在处理所有 ListBox
控件的 GotKeyboardFocus
事件,以检查焦点是否真的属于 ListBox
本身之外的其他人。如果一个项目被 selected,它将被聚焦。如果没有并且列表中至少有一个项目,则第一个项目将获得焦点。这也将隐式 select 它(这是错误的)所以这也是固定的。
这不是本机 Windows 行为的精确复制,因为当焦点位于另一个控件上时它不会保留焦点项。 Windows 表单的 ListBox
区分一个或多个 selected 项目和一个重点项目。每个都被正确跟踪和记住。 WPF 的 ListBox
似乎并不关心项目焦点(很明显,或者这整个可悲的解决方案是不必要的)所以必须做出假设。
这在我的应用程序中运行良好,从用户的角度来看不会让我烦恼。在两个方向上通过控件切换都没有问题。
附件属性实现在ListBoxExtensions
class(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
}
}
将此添加到引用自 App.xaml
的 ResourceDictionary
:
<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>
为了在 WPF window 中使用快捷键,您必须使用 Label
控件。指定要在其 Target
属性 中聚焦的控件,并在热键前加上 _
。这适用于 TextBox
控件,但不适用于 ListBox
。焦点不是 "focused" 项,而是列表框控件本身。然后按箭头键会发生不可预测的事情。这样完全不能用。显然这个问题现在 for ten years 存在。
下面是一些演示代码:
<Label Content="_List:" Target="{Binding ElementName=myList}"/>
<ListBox Name="myList" Items="..."/>
<Button Content="OK"/>
您需要先将一些项目放入列表,然后 select 第二个。单击按钮仅将其聚焦。然后按 Alt+L 聚焦列表。
我应该开始搞乱 ListBox
的 GotFocus
事件来修复焦点吗?或者对此有适当的解决方案吗?我是否错过了一些异国情调 属性 来设置它?
我找到了解决这个问题的方法。它不涉及任何 per-control 定制。根据默认样式,所有必要的事件都会自动附加到所有 ListBox
控件。
我正在处理所有 ListBox
控件的 GotKeyboardFocus
事件,以检查焦点是否真的属于 ListBox
本身之外的其他人。如果一个项目被 selected,它将被聚焦。如果没有并且列表中至少有一个项目,则第一个项目将获得焦点。这也将隐式 select 它(这是错误的)所以这也是固定的。
这不是本机 Windows 行为的精确复制,因为当焦点位于另一个控件上时它不会保留焦点项。 Windows 表单的 ListBox
区分一个或多个 selected 项目和一个重点项目。每个都被正确跟踪和记住。 WPF 的 ListBox
似乎并不关心项目焦点(很明显,或者这整个可悲的解决方案是不必要的)所以必须做出假设。
这在我的应用程序中运行良好,从用户的角度来看不会让我烦恼。在两个方向上通过控件切换都没有问题。
附件属性实现在ListBoxExtensions
class(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
}
}
将此添加到引用自 App.xaml
的 ResourceDictionary
:
<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>