在带有TextBox的ListBox中,如何关注添加的TextBox



我有一个文本框的列表框和一个向列表框添加新项目的按钮。当我单击添加按钮时,我希望新项目被选中,并且包含的文本框具有焦点。

我可以通过绑定轻松地选择新项目,但我还没有弄清楚如何聚焦文本框。我无法从视图模型中执行此操作,因为新的文本框要稍后才能创建。

为了向您展示这个问题,我创建了一个示例解决方案(可在GitHub:TestListBoxWithTextBox上获得(。

这是XAML:

<Window
x:Class="TestListBoxWithTextBox.MainWindow"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
Title="MainWindow"
>
<StackPanel>
<ListBox
ItemsSource="{Binding Items}"
SelectedItem="{Binding SelectedItem}"
>
<ListBox.ItemTemplate>
<DataTemplate>
<TextBox Text="{Binding Name}" />
</DataTemplate>
</ListBox.ItemTemplate>
</ListBox>
<Button
Content="Add"
Command="{Binding AddItemCommand}"
/>
</StackPanel>
</Window>

以下是我的视图模型(ViewModelBase来自MVVM Light Toolkit(:

public class MainViewModel : ViewModelBase
{
public ObservableCollection<ItemViewModel> Items { get; } =
new ObservableCollection<ItemViewModel>();
private ItemViewModel selectedItem;
public ItemViewModel SelectedItem
{
get => selectedItem;
set => Set(nameof(SelectedItem), ref selectedItem, value);
}
public ICommand AddItemCommand =>
new RelayCommand(() =>
{
var newItem = new ItemViewModel();
Items.Add(newItem);
SelectedItem = newItem;
});
}
public class ItemViewModel : ViewModelBase
{
private string name;
public string Name
{
get => name;
set => Set(nameof(Name), ref name, value);
}
}

我尝试过的东西

从视图模型中与视图对话:我使用方法FocusTextBox(int index)创建了一个接口IView。视图实现了这个接口,视图模型在选择新项后调用了它的方法(在AddItemCommand中(。然而,视图无法找到TextBox,因为它还不存在,即使我将新项目添加到了Items列表中。

TextBox集中在其Loaded事件上:Loaded事件保证TextBox存在,因此尝试将焦点集中在那里是有意义的。这在这个简单的例子中有效,但在我的实际程序中无效。在我的程序中,当你在TextBox中输入一些内容,然后按下添加按钮时,焦点就会从文本框中移开,然后它会调用一个单独的命令来对项目进行排序。在排序过程中,一些文本框会被移动,这会导致它们的Loaded事件被调用,然后从添加按钮中窃取焦点,因此它的行为就像从未按下添加按钮一样。

TextBox集中在ListBox.ItemContainingGenerator.StatusChanged事件上:当列表框中所选项目发生更改时,我将收听ItemContainingGenerator.StatusChanged事件。当正在生成或完成生成列表框中的项目时,会触发此事件。当它们生成完成后,我在所选项目(在视图模型中设置(中找到TextBox,并将注意力集中在它上。这个解决方案有效,但并不一致。在我的一些列表框中,这不起作用,我不知道为什么。

我为您的代码添加了一些小的更改。。我认为它有效。。。

试试这个:

<ListBox x:Name="MyListBox"
ItemsSource="{Binding Items}"
SelectedItem="{Binding SelectedItem}"
>
<ListBox.ItemTemplate>
<DataTemplate>
<TextBox MinWidth="100" Text="{Binding Name}" Initialized="TextBoxElement_OnInitialized"/>
</DataTemplate>
</ListBox.ItemTemplate>
</ListBox>

在你的代码后面:

private int _textBoxCounter = 0;
private void TextBoxElement_OnInitialized(object sender, EventArgs e)
{
if (_textBoxCounter < MyListBox.Items.Count)
{
Keyboard.Focus((IInputElement)sender);
_textBoxCounter++;
}
}

这样可以保证在分拣操作期间不会设置焦点

最新更新