首页 > 解决方案 > 在 WPF 中将焦点设置在父 TabItem 上

问题描述

有没有办法自动切换到承载我想要关注的控件的 TabItem?

我的示例窗口来举例说明这个问题。

<Window x:Class="Sample.MainWindow"
        xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
        xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
        xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
        xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
        xmlns:local="clr-namespace:Sample"
        mc:Ignorable="d"
        Title="MainWindow" Height="450" Width="800">

    <Window.Resources>
        <Style TargetType="Button">
            <Setter Property="Width" Value="80"/>
            <Setter Property="Height" Value="24"/>
        </Style>
    </Window.Resources>
    
    <Grid>
        <Grid.RowDefinitions>
            <RowDefinition Height="*"/>
            <RowDefinition Height="auto"/>
        </Grid.RowDefinitions>

        <TabControl Grid.Row="0" Margin="10" Background="White">
            <TabItem Header="TabItem1">
                <Button x:Name="SomeButton" Content="Set Focus on TextBox" Width="120" Click="Button_Click"/>
            </TabItem>
            <TabItem Header="TabItem2">
                <TextBox x:Name="SomeTextBox" Margin="10" Text="Sample text"/>
            </TabItem>
        </TabControl>

        <StackPanel Grid.Row="1" Margin="10">
            <Button Content="Cancel" HorizontalAlignment="Right" Click="Button_Click_1"/>
        </StackPanel>
    </Grid>
</Window>

以及背后的代码:

public partial class MainWindow : Window
{
    public MainWindow()
    {
        InitializeComponent();
    }

    private void Button_Click(object sender, RoutedEventArgs e)
    {
        SomeTextBox.Focus();
    }

    private void Button_Click_1(object sender, RoutedEventArgs e)
    {
        Close();
    }
}

因此,当单击 时SomeButton,我想将焦点移至,SomeTextBox但要使其正常工作,我必须先选择TabItem2。在提供的示例中,这显然很容易,但我正在寻找一种自动化解决方案,它“知道”SomeTextBox属于TabItem2并切换到它,然后将重点放在所需的控件上。不用说,在实际情况下,SomeTextBox可能在VisualTree其他类型的窗格中的其他级别。可能吗?

顺便说一句,如果有帮助,此类功能的应用会将焦点设置在由错误验证突出显示的控件上和/或切换到包含它的窗格。

标签: c#wpfsetfocus

解决方案


您可以使用VisualTreeHelper该类来查找特定类型的最近父级。

这是This answer中的一个实现示例。

public static T FindParentOfType<T>(this DependencyObject child) where T : DependencyObject
{
    DependencyObject parentDepObj = child;
    do
    {
        parentDepObj = VisualTreeHelper.GetParent(parentDepObj);
        T parent = parentDepObj as T;
        if (parent != null) return parent;
    }
    while (parentDepObj != null);
    return null;
}

一旦你有了对你的引用TabItem,你就可以设置它的IsSelected属性来选择它TabControl

private void Button_Click(object sender, RoutedEventArgs e)
{
    var tabItem = FindParentOfType<TabItem>(SomeTextBox);
    if (tabItem is null) return;
    (tabItem as TabItem).IsSelected = true;
    SomeTextBox.Focus();
}

编辑

很好地抓住了在未选择TextBox其父级时不在可视树中的TabItem情况。这是另一种TextBox不依赖于视觉树的方法。

private void Button_Click(object sender, RoutedEventArgs e)
{
    FrameworkElement currentItem = SomeTextBox;
    do
    {
        currentItem = (FrameworkElement)currentItem.Parent;
    }
    while (!(currentItem is TabItem)
           && (currentItem as TabItem).Parent != MyTabControl // Optional handling in case you have nested TabControls
           && !(currentItem.Parent is null));

    (currentItem as TabItem).IsSelected = true;
    currentItem.UpdateLayout();
        
    SomeTextBox.Focus();
}

推荐阅读