39

我有一个UserControl包含一个TextBox. 当我的主窗口加载时,我想将焦点设置到这个文本框,所以我添加Focusable="True" GotFocus="UC_GotFocus"UserControls 定义和FocusManager.FocusedElement="{Binding ElementName=login}"我的主窗口定义中。在该UC_GotFocus方法中,我只需调用.Focus()我想要关注的控件,但这不起作用。

我需要做的就是TextBoxUserControl应用程序启动时获得焦点。

任何帮助将不胜感激,谢谢。

4

18 回答 18

28

我最近为第一次加载主窗口时通过情节提要显示的登录启动画面解决了这个问题。

我相信修复有两个关键。一个是使包含元素成为焦点范围。另一个是处理由正在加载的窗口触发的情节提要的情节提要完成事件。

该故事板使用户名和密码画布可见,然后逐渐变为 100% 不透明。关键是用户名控件在情节提要运行之前不可见,因此该控件在可见之前无法获得键盘焦点。让我失望的是它有“焦点”(即焦点是真的,但事实证明这只是逻辑焦点),直到阅读 Kent Boogaart 之前,我才知道 WPF 有逻辑焦点和键盘焦点的概念回答并查看微软的 WPF链接文本

一旦我这样做了,我的特定问题的解决方案就很简单了:

1)使包含元素成为焦点范围

<Canvas FocusManager.IsFocusScope="True" Visibility="Collapsed">
    <TextBox x:Name="m_uxUsername" AcceptsTab="False" AcceptsReturn="False">
    </TextBox>
</Canvas>

2) 将已完成的事件处理程序附加到情节提要

    <Storyboard x:Key="Splash Screen" Completed="UserNamePassword_Storyboard_Completed">
...
</Storyboard>

3) 将我的用户名 TextBox 设置为在情节提要完成事件处理程序中具有键盘焦点。

void UserNamePassword_Storyboard_Completed(object sender, EventArgs e)
{
 m_uxUsername.Focus();
}

请注意,调用 item.Focus() 会导致调用 Keyboard.Focus(this),因此您无需显式调用 this。请参阅此问题,了解Keyboard.Focus(item) 和 item.Focus 之间的区别。

于 2009-05-07T22:47:59.760 回答
17

它很愚蠢,但它有效:

弹出一个等待一段时间然后返回并设置所需焦点的线程。它甚至可以在元素宿主的上下文中工作。

private void ListView_SelectionChanged(object sender, SelectionChangedEventArgs e)
{

 System.Threading.ThreadPool.QueueUserWorkItem(
                   (a) =>
                        {
                            System.Threading.Thread.Sleep(100);
                            someUiElementThatWantsFocus.Dispatcher.Invoke(
                            new Action(() =>
                            {
                                someUiElementThatWantsFocus.Focus();

                            }));
                        }
                   );

}
于 2009-12-02T22:12:43.723 回答
7

就在最近,我有一个包含一些 TextBlock 的列表框。我希望能够双击文本块并将其变成一个文本框,然后专注于它并选择所有文本,以便用户可以开始输入新名称(类似于 Adob​​e 图层)

无论如何,我正在通过一个活动来做这件事,但它不起作用。对我来说,这里的灵丹妙药是确保我将事件设置为已处理。我认为它正在设置焦点,但是一旦事件沿着路径前进,它就会切换逻辑焦点。

这个故事的寓意是,确保您将事件标记为已处理,这可能是您的问题。

于 2009-03-23T15:48:07.740 回答
7

“在应用程序启动时设置初始焦点时,接收焦点的元素必须连接到 PresentationSource,并且元素必须将 Focusable 和 IsVisible 设置为 true。设置初始焦点的推荐位置是在 Loaded 事件处理程序中”

(MSDN)

只需在窗口(或控件)的构造函数中添加一个“已加载”事件处理程序,然后在该事件处理程序中调用目标控件上的 Focus() 方法。

    public MyWindow() {
        InitializeComponent();
        this.Loaded += new RoutedEventHandler(MyWindow_Loaded);
    }

    void MyWindow_Loaded(object sender, RoutedEventArgs e) {
        textBox.Focus();
    }
于 2010-08-06T06:18:34.657 回答
5

因为我尝试了 fuzquat 的解决方案并发现它是最通用的解决方案,所以我想我会分享一个不同的版本,因为有些人抱怨它看起来很乱。所以这里是:

                casted.Dispatcher.BeginInvoke(new Action<UIElement>(x =>
                {
                    x.Focus();
                }), DispatcherPriority.ApplicationIdle, casted);

没有 Thread.Sleep,没有 ThreadPool。我希望足够干净。真的可以使用一些代表,所以我可以评论其他人的解决方案。

更新:

由于人们似乎喜欢漂亮的代码:

public static class WpfExtensions
{
    public static void BeginInvoke<T>(this T element, Action<T> action, DispatcherPriority priority = DispatcherPriority.ApplicationIdle) where T : UIElement
    {
        element.Dispatcher.BeginInvoke(priority, action);
    }
}

现在你可以这样称呼它:

child.BeginInvoke(d => d.Focus());
于 2013-09-20T09:08:44.430 回答
3

WPF 支持两种不同风格的焦点:

  1. 键盘焦点
  2. 逻辑焦点

FocusedElement属性在焦点范围内获取或设置逻辑焦点。我怀疑你TextBox 确实有逻辑焦点,但它包含的焦点范围不是活动的焦点范围。因此,它没有键盘焦点。

所以问题是,你的视觉树中有多个焦点范围吗?

于 2009-03-23T14:26:07.233 回答
3
  1. 将您的用户控件设置为Focusable="True" (XAML)
  2. 处理控件上的GotFocus事件并调用yourTextBox.Focus()
  3. 处理窗口上的Loaded事件并调用yourControl.Focus()

在我键入时,我有一个使用此解决方案运行的示例应用程序。如果这对您不起作用,则一定是您的应用程序或环境特定的东西导致了问题。在您最初的问题中,我认为绑定导致了问题。我希望这有帮助。

于 2009-09-16T18:30:56.480 回答
3

我发现了一系列关于 WPF 焦点的博客文章。

它们都很好读,但第 3 部分专门处理将焦点设置到 UserControl 中的 UI 元素。

于 2010-07-07T08:48:06.340 回答
2

在经历了“WPF Initial Focus Nightmare”并基于堆栈上的一些答案之后,以下证明对我来说是最好的解决方案。

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

EventManager.RegisterClassHandler(typeof(Window), Window.LoadedEvent,
          new RoutedEventHandler(WindowLoaded));

然后在 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));

        }));
    }

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

我发现以下解决方案最好,因为它在全球范围内用于整个应用程序。

希望能帮助到你...

奥兰

于 2011-01-24T17:37:59.980 回答
1

我注意到一个与在 ElementHosts 中托管 WPF UserControls 相关的焦点问题,这些元素主机包含在通过 MdiParent 属性设置为 MDI 子项的 Form 中。

我不确定这是否与其他人遇到的问题相同,但您可以通过以下链接深入了解详细信息。

在 WindowsForms 子 MDI 表单的 ElementHost 中托管的 WPF UserControl 中设置焦点的问题

于 2009-03-31T20:09:57.497 回答
1

我不喜欢为 UserControl 设置另一个选项卡范围的解决方案。在这种情况下,通过键盘导航时您将有两个不同的插入符号:在窗口上和另一个 - 内部用户控件。我的解决方案只是将焦点从用户控件重定向到内部子控件。将用户控件设置为可聚焦(因为默认情况下为 false):

<UserControl ..... Focusable="True">

并在代码隐藏中覆盖焦点事件处理程序:

protected override void OnGotFocus(RoutedEventArgs e)
{
    base.OnGotFocus(e);
    MyTextBox.Focus();
}

protected override void OnGotKeyboardFocus(KeyboardFocusChangedEventArgs e)
{
    base.OnGotKeyboardFocus(e);
    Keyboard.Focus(MyTextBox);
}
于 2013-10-30T10:17:48.233 回答
1

对我有用的是FocusManager.FocusedElement属性。我首先尝试在 UserControl 上设置它,但它不起作用。

所以我试着把它放在 UserControl 的第一个孩子上:

<UserControl x:Class="WpfApplication3.UserControl1"
         xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
         xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml">
<Grid FocusManager.FocusedElement="{Binding ElementName=MyTextBox, Mode=OneWay}">
    <TextBox x:Name="MyTextBox"/>
</Grid>

......它奏效了!:)

于 2013-12-18T20:02:27.900 回答
1

我将 fuzquat 的答案转换为扩展方法。我正在使用它而不是 Focus() ,其中 Focus() 不起作用。

using System;
using System.Threading;
using System.Windows;

namespace YourProject.Extensions
{
    public static class UIElementExtension
    {
        public static void WaitAndFocus(this UIElement element, int ms = 100)
        {
            ThreadPool.QueueUserWorkItem(f =>
            {
                Thread.Sleep(ms);

                element.Dispatcher.Invoke(new Action(() =>
                {
                    element.Focus();
                }));
            });
        }
    }
}
于 2015-12-01T11:57:23.967 回答
0

我有用户控件 - 带有两个文本框的堆栈面板。文本框是在构造函数中添加的,而不是在 xaml 中。当我尝试关注第一个文本框时,什么也没发生。带有 Loaded 事件的 siggestion 解决了我的问题。刚刚在 Loaded 事件中调用 control.Focus() 和其他任何东西。

于 2011-06-29T14:52:31.280 回答
0

假设您想为用户名文本框设置焦点,因此用户每次出现时都可以直接输入。

在您的控件的构造函数中:

this.Loaded += (sender, e) => Keyboard.Focus(txtUsername);
于 2011-12-23T04:58:05.993 回答
0

在尝试了上述建议的组合之后,我能够可靠地将焦点分配给子 UserControl 上所需的文本框,如下所示。基本上,将焦点放在子控件上,并让子 UserControl 将焦点放在其 TextBox 上。TextBox 的焦点语句本身返回 true,但是直到 UserControl 也获得焦点后才产生所需的结果。我还应该注意,UserControl 无法为自己请求焦点,必须由 Window 提供。

为简洁起见,我没有在 Window 和 UserControl 上注册 Loaded 事件。

窗户

private void OnWindowLoaded(object sender, RoutedEventArgs e)
{
    ControlXYZ.Focus();
}

用户控制

private void OnControlLoaded(object sender, RoutedEventArgs e)
{
    TextBoxXYZ.Focus();
}
于 2012-07-19T19:03:03.947 回答
0

我将它设置在 PageLoaded() 或加载控件中,但随后我调用 WCF 异步服务并做一些似乎失去焦点的事情。我必须在我所做的所有事情的最后设置它。这很好,但有时我对代码进行了更改,然后我忘记了我也在设置光标。

于 2013-08-16T18:14:54.600 回答
-2

在 WPF 用户控件中将键盘焦点设置为画布时,我遇到了同样的问题。我的解决方案

  1. 在 XAML 中将元素设置为Focusable="True"
  2. element_mousemove事件中创建简单检查:

    if(!element.IsKeyBoardFocused)
        element.Focus();
    

就我而言,它工作正常。

于 2012-01-30T13:54:06.000 回答