WPF和初始焦点

Joe*_*ite 179 wpf focus

似乎当WPF应用程序启动时,没有任何焦点.

这真的很奇怪.我使用的每个其他框架都符合您的期望:将初始焦点放在Tab键顺序中的第一个控件上.但我已经确认它是WPF,而不仅仅是我的应用程序 - 如果我创建一个新窗口,只是在其中放置一个TextBox,并运行应用程序,TextBox没有焦点,直到我点击它或按Tab键.呸.

我的实际应用程序比TextBox更复杂.我在UserControls中有几层UserControl.其中一个UserControls有Focusable ="True"和KeyDown/KeyUp处理程序,我希望它在我的窗口打开后立即获得焦点.不过,我仍然是一个WPF新手,而且我没有太多运气搞清楚如何做到这一点.

如果我启动我的应用程序并按Tab键,则焦点转到我的可聚焦控件,它开始以我想要的方式工作.但我不希望我的用户在开始使用窗口之前必须点击Tab.

我已经使用了FocusManager.FocusedElement,但是我不确定将它设置为哪个控件(顶级窗口?包含可聚焦控件的父级?可聚焦控件本身?)或者设置它的内容.

在窗口打开后,我需要做什么才能使我的深层嵌套控件具有初始焦点?或者更好的是,将第一个可聚焦控件聚焦在Tab键顺序中?

Joe*_*ite 156

我有一个聪明的主意,就是通过Reflector来查看Focusable属性的使用位置,并找到了解决这个问题的方法.我只需要将以下代码添加到我的Window的构造函数中:

Loaded += (sender, e) =>
    MoveFocus(new TraversalRequest(FocusNavigationDirection.Next));
Run Code Online (Sandbox Code Playgroud)

这将自动选择Tab键顺序中的第一个控件,因此它是一个通用的解决方案,应该可以放入任何窗口和Just Work.

  • 将其转换为行为.<Window FocusBehavior.FocusFirst ="true"> ... </ Window> (21认同)
  • @wekempf,我不熟悉行为的概念,但我调查了它,这根本不是一个坏主意.如果其他人(像我一样)还不熟悉附加的行为,这里有一个解释:http://www.codeproject.com/KB/WPF/AttachedBehaviors.aspx (6认同)

小智 155

这也有效:

<Window FocusManager.FocusedElement="{Binding ElementName=SomeElement}">

   <DataGrid x:Name="SomeElement">
     ...
   </DataGrid>
</Window>
Run Code Online (Sandbox Code Playgroud)

  • 似乎在UserControls中不起作用. (28认同)
  • 我很惊讶我是第一个对此发表评论的人.我很困惑,因为它几乎可以进行任何控制.在回答这个具体问题,我觉得它会去的窗口,但你可以阅读http://msdn.microsoft.com/en-us/library/system.windows.input.focusmanager%28v=vs的言论.110%29.aspx了解您如何控制此事. (4认同)

Miz*_*zor 59

基于作为附加行为实现的已接受答案:

using System.Windows;
using System.Windows.Controls;
using System.Windows.Input;

namespace UI.Behaviors
{
    public static class FocusBehavior
    {
        public static readonly DependencyProperty FocusFirstProperty =
            DependencyProperty.RegisterAttached(
                "FocusFirst",
                typeof(bool),
                typeof(FocusBehavior),
                new PropertyMetadata(false, OnFocusFirstPropertyChanged));

        public static bool GetFocusFirst(Control control)
        {
            return (bool)control.GetValue(FocusFirstProperty);
        }

        public static void SetFocusFirst (Control control, bool value)
        {
            control.SetValue(FocusFirstProperty, value);
        }

        static void OnFocusFirstPropertyChanged(
            DependencyObject obj, DependencyPropertyChangedEventArgs args)
        {
            Control control = obj as Control;
            if (control == null || !(args.NewValue is bool))
            {
                return;
            }

            if ((bool)args.NewValue)
            {
                control.Loaded += (sender, e) =>
                    control.MoveFocus(new TraversalRequest(FocusNavigationDirection.Next));
            }
        }
    }
}
Run Code Online (Sandbox Code Playgroud)

像这样使用它:

<Window xmlns:Behaviors="clr-namespace:UI.Behaviors"
        Behaviors:FocusBehavior.FocusFirst="true">
Run Code Online (Sandbox Code Playgroud)

  • 在我看来,这是*到目前为止*我找到的最佳解决方案.谢谢! (6认同)

Joe*_*ite 14

我找到了另一种可能的解 Mark Smith发布了一个FirstFocusedElement标记扩展,用于与FocusManager.FocusedElement一起使用.

<UserControl x:Class="FocusTest.Page2"
    xmlns:FocusTest="clr-namespace:FocusTest"
    FocusManager.FocusedElement="{FocusTest:FirstFocusedElement}">
Run Code Online (Sandbox Code Playgroud)


OrP*_*Paz 8

在进行了"WPF初始焦点噩梦"并基于堆栈上的一些答案后,以下证明我是最佳解决方案.

首先,添加您的App.xaml OnStartup()以下内容:

EventManager.RegisterClassHandler(typeof(Window), Window.LoadedEvent,
          new RoutedEventHandler(WindowLoaded));
Run Code Online (Sandbox Code Playgroud)

然后在App.xaml中添加'WindowLoaded'事件:

void WindowLoaded(object sender, RoutedEventArgs e)
    {
        var window = e.Source as Window;
        System.Threading.Thread.Sleep(100);
        window.Dispatcher.Invoke(
        new Action(() =>
        {
            window.MoveFocus(new TraversalRequest(FocusNavigationDirection.First));

        }));
    }
Run Code Online (Sandbox Code Playgroud)

必须使用线程问题,因为WPF的初始焦点主要是由于某些框架竞争条件而失败.

我发现以下解决方案最好,因为它在整个应用程序中全局使用.

希望能帮助到你...

奥兰

  • 使用`BeginInvoke`而不是那个可怕的`Sleep(100)`语句. (3认同)

Vla*_*k Y 8

有同样的问题用简单的解决方案解决了它:在主窗口中:

  <Window ....
        FocusManager.FocusedElement="{Binding ElementName=usercontrolelementname}"
         ... />
Run Code Online (Sandbox Code Playgroud)

在用户控件中:

private void UserControl_GotFocus_1(object sender, RoutedEventArgs e)
        {
            targetcontrol.Focus();
            this.GotFocus -= UserControl_GotFocus_1;  // to set focus only once
        }
Run Code Online (Sandbox Code Playgroud)

  • 仅当控件直接位于Window内时才有效,而不是嵌套在UserControl中. (3认同)

Sim*_*bee 8

您可以轻松地将控件设置为XAML中的焦点元素.

<Window>
   <DataGrid FocusManager.FocusedElement="{Binding RelativeSource={RelativeSource Self}}">
     ...
   </DataGrid>
</Window>
Run Code Online (Sandbox Code Playgroud)

我从来没有尝试在用户控件中设置它,看看它是否有效,但它可能.