【发布时间】:2019-11-14 04:10:02
【问题描述】:
我有一个文本框列表框和一个用于向列表框添加新项目的按钮。当我点击添加按钮时,我希望新项目被选中并且包含的文本框具有焦点。
我可以通过绑定轻松选择新项目,但我还没有弄清楚如何聚焦文本框。我无法从视图模型中执行此操作,因为新文本框要到稍后才会创建。
为了向您展示问题,我创建了一个示例解决方案(可在 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 并专注于它。该解决方案有效,但并非始终如一。在我的某些列表框中,这不起作用,我不确定为什么。
【问题讨论】: