无法将焦点设置到 UserControl 的子级

发布于 2024-07-15 01:55:26 字数 448 浏览 6 评论 0原文

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

我需要做的就是让 UserControl 中的 TextBox 在应用程序启动时接收焦点。

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

I have a UserControl which contains a TextBox. When my main window loads I want to set the focus to this textbox so I added Focusable="True" GotFocus="UC_GotFocus" to the UserControls definition and FocusManager.FocusedElement="{Binding ElementName=login}" to my main windows definition. In the UC_GotFocus method i simply call .Focus() on the control i want to focus on but this doesn't work.

All i need to do is have a TextBox in a UserControl receive focus when the application starts.

Any help would be appreciated, thanks.

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(18

娜些时光,永不杰束 2024-07-22 01:55:26

我最近修复了首次加载主窗口时通过故事板显示的登录初始屏幕的问题。

我相信解决这个问题有两个关键。 一种是使包含元素成为焦点范围。 另一个是处理由正在加载的窗口触发的故事板的 Storyboard Completed 事件。

此故事板使用户名和密码画布可见,然后逐渐变为 100% 不透明。 关键是用户名控件在故事板运行之前不可见,因此该控件在可见之前无法获得键盘焦点。 让我有一段时间感到困惑的是它有“焦点”(即焦点是正确的,但事实证明这只是逻辑焦点),直到阅读 Kent Boogaart 的文章之前我并不知道 WPF 具有逻辑焦点和键盘焦点的概念回答并查看 Microsoft 的 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),因此您不需要显式调用它。 请参阅有关 Keyboard.Focus(item) 和项目.焦点。

I recently fixed this problem for a login splash screen that is being displayed via a storyboard when the main window is first loaded.

I believe there were two keys to the fix. One was to make the containing element a focus scope. The other was to handle the Storyboard Completed event for the storyboard that was triggered by the window being loaded.

This storyboard makes the username and password canvas visible and then fades into being 100% opaque. The key is that the username control was not visible until the storyboard ran and therefore that control could not get keyboard focus until it was visible. What threw me off for awhile was that it had "focus" (i.e. focus was true, but as it turns out this was only logical focus) and I did not know that WPF had the concept of both logical and keyboard focus until reading Kent Boogaart's answer and looking at Microsoft's WPF link text

Once I did that the solution for my particular problem was straightforward:

1) Make the containing element a focus scope

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

2) Attach a Completed Event Handler to the Storyboard

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

and

3) Set my username TextBox to have the keyboard focus in the storyboard completed event handler.

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

Note that calling item.Focus() results in the call Keyboard.Focus(this), so you don't need to call this explicitly. See this question about the difference between Keyboard.Focus(item) and item.Focus.

乄_柒ぐ汐 2024-07-22 01:55:26

它很愚蠢,但很有效:

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

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();

                            }));
                        }
                   );

}

Its stupid but it works:

Pop a thread that waits a while then comes back and sets the focus you want. It even works within the context of an element host.

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();

                            }));
                        }
                   );

}
伊面 2024-07-22 01:55:26

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

无论如何,我正在做这与一个事件有关,但它不起作用。 对我来说,最重要的是确保我将事件设置为要处理的。 我认为它正在设置焦点,但是一旦事件沿着路径走下去,它就会切换逻辑焦点。

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

Just recently I had a list-box that housed some TextBlocks. I wanted to be able to double click on the text block and have it turn into a TextBox, then focus on it and select all the text so the user could just start typing the new name (Akin to Adobe Layers)

Anyway, I was doing this with an event and it just wasn't working. The magic bullet for me here was making sure that I set the event to handled. I figure it was setting focus, but as soon as the event went down the path it was switching the logical focus.

The moral of the story is, make sure you're marking the event as handled, that might be your issue.

温柔女人霸气范 2024-07-22 01:55:26

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

(MSDN)

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

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

    void MyWindow_Loaded(object sender, RoutedEventArgs e) {
        textBox.Focus();
    }

“When setting initial focus at application startup, the element to
receive focus must be connected to a PresentationSource and the
element must have Focusable and IsVisible set to true. The recommended
place to set initial focus is in the Loaded event handler"

(MSDN)

Simply add a "Loaded" event handler in the constructor of your Window (or Control), and in that event handler call the Focus() method on the target control.

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

    void MyWindow_Loaded(object sender, RoutedEventArgs e) {
        textBox.Focus();
    }
土豪我们做朋友吧 2024-07-22 01:55:26

因为我尝试了 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());

since i tried a fuzquat's solution and found it the most generic one, i thought i'd share a different version, since some complained about it looking messy. so here it is:

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

no Thread.Sleep, no ThreadPool. Clean enough i hope.

UPDATE:

Since people seem to like pretty code:

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);
    }
}

now you can call it like this:

child.BeginInvoke(d => d.Focus());
甜味拾荒者 2024-07-22 01:55:26

WPF 支持两种不同类型的焦点:

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

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

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

WPF supports two different flavors of focus:

  1. Keyboard focus
  2. Logical focus

The FocusedElement property gets or sets logical focus within a focus scope. I suspect your TextBox does have logical focus, but its containing focus scope is not the active focus scope. Ergo, it does not have keyboard focus.

So the question is, do you have multiple focus scopes in your visual tree?

谁人与我共长歌 2024-07-22 01:55:26

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

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

I found a good series of blog posts on WPF focus.

They are all good to read, but the 3rd part specifically deals with setting focus to a UI element in a UserControl.

骑趴 2024-07-22 01:55:26
  1. 将用户控件设置为 Focusable="True" (XAML)
  2. 处理控件上的 GotFocus 事件并调用 yourTextBox.Focus()
  3. 处理窗口上的 Loaded 事件并调用 yourControl.Focus()

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

  1. Set your user control to Focusable="True" (XAML)
  2. Handle the GotFocus event on your control and call yourTextBox.Focus()
  3. Handle the Loaded event on your window and call yourControl.Focus()

I have a sample app running with this solution as I type. If this does not work for you, there must be something specific to your app or environment that causes the problem. In your original question, I think the binding is causing the problem.
I hope this helps.

南…巷孤猫 2024-07-22 01:55:26

在经历了“WPF 初始焦点噩梦”并基于堆栈上的一些答案之后,以下内容对我来说是最好的解决方案。

首先,添加您的 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 初始焦点大多由于某些框架竞争条件而失败。

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

希望它有帮助...

奥兰

After having a 'WPF Initial Focus Nightmare' and based on some answers on stack, the following proved for me to be the best solution.

First, add your App.xaml OnStartup() the followings:

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

Then add the 'WindowLoaded' event also in App.xaml :

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));

        }));
    }

The threading issue must be use as WPF initial focus mostly fails due to some framework race conditions.

I found the following solution best as it is used globally for the whole app.

Hope it helps...

Oran

做个少女永远怀春 2024-07-22 01:55:26

对我来说,窍门是 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>

...并且成功了! :)

What did the trick for me was the FocusManager.FocusedElement attribute. I first tried to set it on the UserControl, but it didn't work.

So I tried putting it on the UserControl's first child instead:

<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>

... and it worked! :)

长亭外,古道边 2024-07-22 01:55:26

我将 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();
                }));
            });
        }
    }
}

I converted fuzquat's answer to an extension method. I'm using this instead of Focus() where Focus() did not work.

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();
                }));
            });
        }
    }
}
才能让你更想念 2024-07-22 01:55:26

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

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

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

I've noticed a focus issue specifically related to hosting WPF UserControls within ElementHosts which are contained within a Form that is set as an MDI child via the MdiParent property.

I'm not sure if this is the same issue others are experiencing but you dig into the details by following the link below.

Issue with setting focus within a WPF UserControl hosted within an ElementHost in a WindowsForms child MDI form

清泪尽 2024-07-22 01:55:26

我不喜欢为 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);
}

I don't like solutions with setting another tab scope for UserControl. In that case, you will have two different carets when navigating by keyboard: on the window and the another - inside user control. My solution is simply to redirect focus from user control to inner child control. Set user control focusable (because by default its false):

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

and override focus events handlers in code-behind:

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

protected override void OnGotKeyboardFocus(KeyboardFocusChangedEventArgs e)
{
    base.OnGotKeyboardFocus(e);
    Keyboard.Focus(MyTextBox);
}
滥情空心 2024-07-22 01:55:26

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

I have user control - stack panel with two text boxes.The text boxes were added in contructor, not in the xaml. When i try to focus first text box, nothing happend.
The siggestion with Loaded event fix my problem. Just called control.Focus() in Loaded event and everthing.

你丑哭了我 2024-07-22 01:55:26

假设您想为用户名文本框设置焦点,以便用户可以在每次显示时直接输入。

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

this.Loaded += (sender, e) => Keyboard.Focus(txtUsername);

Assuming you want to set focus for Username textbox, thus user can type in directly every time it shows up.

In Constructor of your control:

this.Loaded += (sender, e) => Keyboard.Focus(txtUsername);
冷夜 2024-07-22 01:55:26

在尝试上述建议的组合后,我能够使用以下内容可靠地将焦点分配给子 UserControl 上的所需文本框。 基本上,将焦点赋予子控件,并让子 UserControl 将焦点赋予其 TextBox。 TextBox 的 focus 语句本身返回 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();
}

After trying combinations of the suggestions above, I was able to reliably assign focus to a desired text box on a child UserControl with the following. Basically, give focus to the child control and have the child UserControl give focus to its TextBox. The TextBox's focus statement returned true by itself, however did not yield the desired result until the UserControl was given focus as well. I should also note that the UserControl was unable to request focus for itself and had to be given by the Window.

For brevity I left out registering the Loaded events on the Window and UserControl.

Window

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

UserControl

private void OnControlLoaded(object sender, RoutedEventArgs e)
{
    TextBoxXYZ.Focus();
}
装迷糊 2024-07-22 01:55:26

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

I set it in the PageLoaded() or control loaded, but then I'm calling WCF async service and doing stuff that seems to lose the focus. I have to to set it at the end of all the stuff I do. That's fine and all, but sometimes I make changes to the code and then I forget that I'm also setting the cursor.

┊风居住的梦幻卍 2024-07-22 01:55:26

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

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

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

就我而言,它工作正常。

I had same problem with setting keyboard focus to canvas in WPF user control.
My solution

  1. In XAML set element to Focusable="True"
  2. In element_mousemove event create simple check:

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

In my case it works fine.

~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文