c# - WPF:在输入时将焦点移至 ItemsControl 中的下一个项目

标签 c# wpf listbox

WPF:当用户在 ItemsControl 的文本框内按下回车键时,我想将焦点移动到 ItemsControl 中下一项的文本框,或者如果用户在最后一项中则创建一个新文本框。

更清楚一点:

场景 1

ItemsControl items:
[ textbox in item 1 ] <- user is here
[ textbox in item 2 ]
[ textbox in item 3 ]

按回车后:

[ textbox in item 1 ]
[ textbox in item 2 ] <- user is here
[ textbox in item 3 ]

情景 2

Items控制项目:

[ textbox in item 1 ]
[ textbox in item 2 ]
[ textbox in item 3 ] <- user is here

按回车后:

[ textbox in item 1 ]
[ textbox in item 2 ]
[ textbox in item 3 ]
[ textbox in item 4 ] <- user is here

如果有帮助,这里是项目数据模板的代码:

<ItemsControl.ItemTemplate>
    <DataTemplate>
        <Grid Background="White">
            <Grid.ColumnDefinitions>
                <ColumnDefinition Width="*"/>
                <ColumnDefinition Width="32"/>
            </Grid.ColumnDefinitions>
            <TextBox Text="{Binding Path=PartName, FallbackValue='----',TargetNullValue='----', NotifyOnSourceUpdated=True}" KeyDown="TextBox_KeyDown"/>
            <Button Grid.Column="1" FontSize="10" x:Name="DeletePartButton" Click="DeletePartButton_Click" Height="22">Usuń</Button>
        </Grid>
    </DataTemplate>
</ItemsControl.ItemTemplate>

编辑 2: 我使用 ItemsControl 是因为不需要选择功能。

编辑 3: 我找到了部分解决方案。它适用于将焦点移动到下一个元素,而不是新元素(这是这里最重要的功能)

    private void PartNameTextBox_KeyDown(object sender, KeyEventArgs e)
    {
        var box = (TextBox)sender;

        if (e.Key == Key.Enter)
        {
            var part = (PiecePart)box.DataContext;
            int index = part.ParentPiece.Parts.IndexOf(part);
            if (index == part.ParentPiece.PartCount - 1)
            {
                part.ParentPiece.Parts.Add(new PiecePart(GetNewPartName(part.ParentPiece)));
                bool success = PartListBox.ApplyTemplate();
                // try to force wpf to build a visual tree for the new item success = false :(
            }
// throws out of bounds exception if a new item was added (and wasn't added to a visual tree)
            var el = ((UIElement)VisualTreeHelper.GetChild(VisualTreeHelper.GetChild(VisualTreeHelper.GetChild(VisualTreeHelper.GetChild(VisualTreeHelper.GetChild(VisualTreeHelper.GetChild(VisualTreeHelper.GetChild(VisualTreeHelper.GetChild(PartListBox, 0),0),1),0),0),++index),0),0));
            el.Focus();
        }
    }

最佳答案

在TextBox的PreviewKeyDown

private void TextBox_PreviewKeyDown(object sender, KeyEventArgs e)
{
 if (e.Key == Key.Enter)
  {
   var txt= sender as TextBox;
   var selecteditem=FindParent<ListBoxItem>(txt);
   int index = ListBox.ItemContainerGenerator.IndexFromContainer(selecteditem);
   if(index<ListBox.Items.Count)
    {
    var afterItem=(ListBoxItem)ListBox.ItemContainerGenerator.ContainerFromIndex(index+1);
    TextBox tbFind = GetDescendantByType(afterItem, typeof (TextBox), "TextBox") as TextBox;
    if (tbFind != null)
    {
     FocusHelper.Focus(tbFind);
    }
   }
  }
}

public static Visual GetDescendantByType(Visual element, Type type, string name)
{
 if (element == null) return null;
 if (element.GetType() == type)
 {
  FrameworkElement fe = element as FrameworkElement;
  if (fe != null)
  {
     if (fe.Name == name)
     {
        return fe;
     }
  }
 }
Visual foundElement = null;
if (element is FrameworkElement)
  (element as FrameworkElement).ApplyTemplate();
for (int i = 0;
    i < VisualTreeHelper.GetChildrenCount(element);
    i++)
{
  Visual visual = VisualTreeHelper.GetChild(element, i) as Visual;
  foundElement = GetDescendantByType(visual, type, name);
  if (foundElement != null)
     break;
}
return foundElement;
}

public static T FindParent<T>(DependencyObject child) where T : DependencyObject
{
 //get parent item
DependencyObject parentObject = VisualTreeHelper.GetParent(child);

//we've reached the end of the tree
if (parentObject == null) return null;

//check if the parent matches the type we're looking for
T parent = parentObject as T;
if (parent != null)
    return parent;
else
    return FindParent<T>(parentObject);
}

还有一个助手可以将 Focus 设置在 TextBox 上:

public static class FocusHelper
{
public static void Focus(UIElement element)
{
 element.Dispatcher.BeginInvoke(DispatcherPriority.Input, new ThreadStart(delegate()
 {
    element.Focus();
 }));
}
}

关于c# - WPF:在输入时将焦点移至 ItemsControl 中的下一个项目,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/29028263/

相关文章:

c# - 压缩字典中的所有列表

c# - HttpClient-向Get请求添加参数

c# - WPF Canvas VisibilityChanged 事件

c# - 如何将 XML "row"加载到列表框 C# 的索引中

c# - 在 ASP.Net (C#) 中,HTML Table 没有 'COLUMN' 属性,怎么办?

c# - WPF 为绑定(bind)的 ComboBox 更正编程绑定(bind)

wpf - 如何在WPF ListView中获取光标下的项目

c# - 在 wpf 中创建自定义用户控件以供重用

vba - excel 2010 vba 如何声明列表框?

c# - WPF ListBox 按钮选择的项目