在XAML WPF中将焦点设置在文本框上

100

尽管在这个论坛和其他论坛上有一些帖子,但我找不到告诉我如何在TextBox上设置焦点的内容。

我有一个包含多个标签和文本框的用户控件。当加载表单时,我想要特定的文本框具有焦点。

我已经设置了tabIndex,但似乎没有起作用。

有什么建议吗?


可能是WPF和初始焦点的重复问题。 - Ruben Bartelink
10个回答

189
你可以使用 FocusManager.FocusedElement 附加属性来实现此目的。下面是一段设置 TxtB 默认聚焦的代码示例。
<StackPanel Orientation="Vertical" FocusManager.FocusedElement="{Binding ElementName=TxtB}">
    <TextBox x:Name="TxtA" Text="A" />
    <TextBox x:Name="TxtB" Text="B" />
</StackPanel>
你也可以在代码中使用TxtB.Focus(),如果你不想在XAML中实现这个功能。

14
@TarkaDaal: “it didn't work for me”这个评论可以更详细一些。可能是因为其他控件抢了焦点。在WPF中,当焦点战争开始时,事情往往变得混乱!请检查您的控件以及您当前在可视树中的位置(例如,在ComboBox模板内部,这将没有效果,并且还有许多其他类似的情况)。如果找不到窃取者,请使用行为或代码后台在加载时将焦点设置为控件。 - Julien Lebosquain
成员“FocusedElement”未被识别或无法访问。:( https://plus.google.com/photos/+HendyIrawan/albums/5990385944888867505/5991104640269523954 - Hendy Irawan
@HendyIrawan 那是银光项目吗,也许? - MojoFilter
1
我正在使用WPF 4.5版本。 FocusManager.FocusedElement 完全没有任何作用。我有什么遗漏吗? - Jordan
看起来如果 StackPanel 在 TreeView 中存在一些小问题,但是这对我们的 NuGet Package Explorer 自定义工作正常。谢谢 :) - iCollect.it Ltd
显示剩余5条评论

27
您可以直接在TextBox上应用该属性:
<TextBox Text="{Binding MyText}" FocusManager.FocusedElement="{Binding RelativeSource={RelativeSource Self}}"/>

18
对我来说没有用,但在容器上设置FocusManager.FocusedElement="{Binding ElementName=TxtB}"有效。 - Grant
1
运行得非常好,不需要任何命名。 - Simon Mattes
1
对我也没用。我们有什么遗漏吗? - BrunoLM
1
我也尝试了,但没有成功。Julien Lebosquain的建议有效。 - Crypt32
2
我也无法工作。所有提出的其他方法也都不起作用。这个问题应该很基本,应该很容易解决...这就是为什么许多人不喜欢WPF的原因。 - IgorStack
显示剩余3条评论

8

我刚开始使用WPF,在阅读上面的例子时,我尝试使用给出的xaml代码示例来设置文本框的焦点,但是以上所有示例都不起作用。

我发现我必须将FocusManager.FocusElement放置在页面元素中。如果您使用窗口作为父元素,这可能也适用。不管怎样,这是对我有效的代码:

 <Page x:Class="NameOfYourClass"
  xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
  xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
  xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006" 
  xmlns:d="http://schemas.microsoft.com/expression/blend/2008" 
  mc:Ignorable="d"
  Title="Title" 
  Height="720"
  Width="915"
  Background="white"
  Loaded="pgLoaded"
  FocusManager.FocusedElement="{Binding ElementName=NameOfYourTextBox}">

  <!-- Create child elements here. -->

  </Page>

3

我有一个位于DataTemplate中的Grid内部的TextBox,当它变得可见时,我希望它能够获得键盘焦点。我还发现

<DataTemplate x:Key="DistanceView" DataType="{x:Type vm:ROI}">
    <Grid FocusManager.FocusedElement="{Binding ElementName=tbDistance}">
        <TextBox x:Name="tbDistance" Grid.Column="1" Grid.Row="1" VerticalAlignment="Bottom"/>
    </Grid>
</DataTemplate>

对我来说没有起作用。

但是当我在父ContentControl中调用Focus()时

private void ContentControl_IsVisibleChanged(object sender, DependencyPropertyChangedEventArgs e)
{
    if ((sender as ContentControl).IsVisible)
    {
        (sender as ContentControl).Focus();
    }
}

当文本框中的光标显示时,表示程序已开始运行。我认为要使FocusManager.FocusedElement属性生效,必须将焦点给予FocusScope。

Jerry


不错的解决方案。这就是我必须做的,因为其他答案方法似乎都不起作用。在我的情况下,我有一组选项卡形式,并且需要在选项卡变为可见时设置焦点。 - Tim Holt

1

Usage: local:FocusManager.FocusOnLoad="True"

    public class FocusManager
    {
        public static readonly DependencyProperty FocusOnLoad = DependencyProperty.RegisterAttached(
            "FocusOnLoad",
            typeof(bool),
            typeof(FocusManager),
            new UIPropertyMetadata(false, new PropertyChangedCallback(OnValueChanged))
            );

        private static void OnValueChanged(DependencyObject sender, DependencyPropertyChangedEventArgs e)
        {
            if (!(sender is Control control))
                return;

            if ((bool) e.NewValue == false)
                return;

            control.Loaded += (s, e) => control.Focus();
        }

        public static bool GetFocusOnLoad(DependencyObject d) => (bool) d.GetValue(FocusOnLoad);

        public static void SetFocusOnLoad(DependencyObject d, bool value) => d.SetValue(FocusOnLoad, value);
    }

1

从实验中得知,XAML解决方案

FocusManager.FocusedElement="{Binding ElementName=yourElement}"

似乎最好将其放置在窗口层次结构的最高元素中(通常是Window,或您放置其他所有内容的Grid)。

有趣的观察。也许这可以解释为什么这里报告了那么多其他失败。 - Bent Tranberg

0

在智能感知中找不到FocusManager有点让我困惑。我只是输入了整个属性,然后它就起作用了。

FocusManager.FocusedElement="{Binding ElementName=MyTextBox}"


微软Visual Studio企业版2015版本14.0.23107.0/C#/WPF


0

为了完整起见,还有一种处理方式是从代码后台处理(例如,在动态创建控件且在XAML中不存在的情况下)。将处理程序附加到窗口的Loaded事件,然后使用所需控件的“.Focus()”方法。以下是一个简单的示例。

public class MyWindow
{
    private VisualCollection controls;
    private TextBox textBox;

    // constructor
    public MyWindow()
    {
        controls = new VisualCollection(this);
        textBox = new TextBox();
        controls.Add(textBox);

        Loaded += window_Loaded;
    }

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

这确实可以工作,但请记住事件永远不会被取消挂钩,这将防止类被处理,这是潜在的内存泄漏。 - Dave
将以下与编程有关的内容从英语翻译成中文。仅返回翻译后的文本: 为了正确起见,我应该说“垃圾收集”而不是“处理”。 - Dave

-1
进一步回复我的 2022 年 2 月 04 日的评论,我是这样解决的:
在 XAML 中的 UserControl 定义中添加 Loaded 事件处理程序。(在 Loaded= 后按 tab 键会自动将事件处理程序添加到代码后面)
然后在代码后台编辑事件处理程序:
private void UserControl_Loaded(object sender, RoutedEventArgs e)
{
    expressionTextBox.Focus();
}

我希望WPF足够聪明,可以在某个时刻处理事件的解绑,使得该类可以被垃圾回收而不会引起内存泄漏,但我不确定。如果有任何意见,我很感兴趣。

-1
将您想要指向焦点的元素绑定为:
FocusManager.FocusedElement= "{Binding ElementName= Comobox1}"

在网格或分组框等中


4
嗯,谢谢你提供和其他人一样的答案...四年后... - Adam Plocher
5
不错,你让Sulfian永久离开了Stack Overflow。一条"欢迎来到Stack Overflow"的信息可能更加合适。 - Contango
2
@Contango:"上次出现是在2014年11月11日"。他在亚当发表评论之前就已经消失得无影无踪了 :) - iCollect.it Ltd
投票反对,因为这是已接受并得到最多赞的答案的重复,所以最好让它消失。 - Bent Tranberg

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接