打开 Window 时,如何将数据模板化的文本框聚焦在 Window 中 ItemsControl 的第一个元素中? (C#, WPF)

How to focus a datatemplated TextBox in the first element of an ItemsControl in a Window, when the Window is opened? (C#, WPF)

当用户单击应用程序中的按钮时,会打开一个 window。我希望属于 ItemsControl 中第一项的 TextBox 获得焦点,以便用户可以在 Window 打开后立即开始键入,而无需手动 select TextBox。

如何做到这一点?

为简单起见,我们可以说 Window 大致如下所示:

<Window>
    <Grid>
        <ItemsControl ItemsSource="{Binding MyItems}">
            <DataTemplate>
                <Grid>
                    <StackPanel>
                        <StackPanel>
                            <customControls:ValidationControl>
                                <TextBox Text="" />
                            </customControls:ValidationControl>
                        </StackPanel>
                    </StackPanel>
                </Grid>
            </DataTemplate>
        </ItemsControl>
    </Grid>
</Window>

更新 在查看了建议的答案和这个 link 之后: Window Loaded and WPF 修改后的解决方案如下:

<Window>
    <Grid>
        <ItemsControl x:Name="myItemsControl" ItemsSource="{Binding MyItems}">
            <DataTemplate>
                <Grid>
                    <StackPanel>
                        <StackPanel>
                            <customControls:ValidationControl>
                                <TextBox Text="" />
                            </customControls:ValidationControl>
                        </StackPanel>
                    </StackPanel>
                </Grid>
            </DataTemplate>
        </ItemsControl>
    </Grid>
</Window>

在构造函数中:

this.Loaded += new RoutedEventHandler(ThisWindowLoaded);

加载方法:

private void ThisWindowLoaded(object sender, RoutedEventArgs e)
{
    var textbox = FindVisualChild<TextBox>(myItemsControl.ItemContainerGenerator.ContainerFromIndex(0));
    FocusManager.SetFocusedElement(myItemsControl, textbox);
}

超级骗子方法:

public static T FindVisualChild<T>(DependencyObject depObj) where T : DependencyObject
{
    if (depObj != null)
    {
        for (int i = 0; i < VisualTreeHelper.GetChildrenCount(depObj); i++)
        {
            DependencyObject child = VisualTreeHelper.GetChild(depObj, i);
            if (child != null && child is T)
            {
                return (T)child;
            }

            T childItem = FindVisualChild<T>(child);
            if (childItem != null)
                return childItem;
        }
    }
    return null;
}

如果是 WPF 你应该像下面那样做 smt :

<Grid>
        <DataGridCell>
            <Grid>
                <TextBox x:Name="TextBox1" Text=" ">

                    </TextBox>
            </Grid>
        </DataGridCell>

</Grid>

和代码隐藏:

 TextBox1.Focus();

FocusManager.SetFocusedElement() 可能就是您要查找的内容。

Xaml

   <ItemsControl x:Name="ItemsControl">
        <ItemsControl.ItemTemplate>
            <DataTemplate>
                <TextBox />
            </DataTemplate>
        </ItemsControl.ItemTemplate>
    </ItemsControl> 

在 Loaded 事件中,您关注第一个文本框:

   var textbox = ItemsControl.ItemContainerGenerator.ContainerFromIndex(0).FindChildByType<TextBox>();
   FocusManager.SetFocusedElement(ItemsControl, textbox);

以下是我先找到的方法child:

  public static T FindVisualChild<T>(DependencyObject depObj) where T : DependencyObject
    {
        if (depObj != null)
        {
            for (int i = 0; i < VisualTreeHelper.GetChildrenCount(depObj); i++)
            {
                DependencyObject child = VisualTreeHelper.GetChild(depObj, i);
                if (child != null
                    && child is T)
                {
                    return (T)child;
                }

                T childItem = FindVisualChild<T>(child);
                if (childItem != null)
                    return childItem;
            }
        }
        return null;
    }

如果有人对以下内容感兴趣: 在我的情况下,ItemsControl 有几个不同的 DataTemplates 用于不同类型的项目。有些是可编辑的,有些不是。这就是为什么我无法判断当前在哪个项目中显示哪种编辑器。 所以我在寻找不同的解决方案: 我注意到,当我按一次 Tab 键时(在对话框打开后),焦点移动到 ItemsControl 中的预期元素。 这就是为什么我在加载事件中生成一个选项卡:

this.Dispatcher.BeginInvoke(DispatcherPriority.ApplicationIdle, (Action)delegate
{
    this.MoveFocus(new TraversalRequest(FocusNavigationDirection.Next));
});