C# 在Tab键上向列表框添加新项目
我有一个WPF列表框,其中有一个用于列表框ItemTemplate的自定义数据模板(每个项目都有一组控件;即文本框和日期选择器)。最后一个日期选择器附带了一个行为,允许用户在PreviewKeyDown事件的事件处理程序中执行ICommand 这样做的目的是,用户将通过ListBoxItem中的控件进行TAB,当它们到达最后一个控件时,再次按TAB键,一个新的ListBoxItem get将添加到ListBox中。然后焦点将移动到下一个ListBoxItem中的第一个控件。如果列表框中已经有2个项目,并且您正在切换第一个项目,则我的解决方案可以正常工作。如果ListBox中只有1个项,并且您到达最后一个控件,则会添加新的ListBoxItem(如预期的那样),但焦点会从ListBox移到下一个父控件 这就像调用行为代码和ICommand一样,但是TAB事件继续进行,而不等待添加新的ListBoxItem 有什么建议吗 我的行为(ZBehaviorBase只是一个允许“更好”清理的类):C# 在Tab键上向列表框添加新项目,c#,wpf,listbox,listboxitem,attachedbehaviors,C#,Wpf,Listbox,Listboxitem,Attachedbehaviors,我有一个WPF列表框,其中有一个用于列表框ItemTemplate的自定义数据模板(每个项目都有一组控件;即文本框和日期选择器)。最后一个日期选择器附带了一个行为,允许用户在PreviewKeyDown事件的事件处理程序中执行ICommand 这样做的目的是,用户将通过ListBoxItem中的控件进行TAB,当它们到达最后一个控件时,再次按TAB键,一个新的ListBoxItem get将添加到ListBox中。然后焦点将移动到下一个ListBoxItem中的第一个控件。如果列表框中已经有2个
公共类TabOffCommandBehavior:ZBehaviorBase
{
公共ICommand命令
{
获取{return(ICommand)GetValue(CommandProperty);}
set{SetValue(CommandProperty,value);}
}
公共静态只读DependencyProperty CommandProperty=
Register(“TabCommand”、typeof(ICommand)、typeof(TabOffCommandBehavior));
受保护的覆盖无效初始化()
{
this.AssociatedObject.PreviewKeyDown+=新的KeyEventHandler(AssociatedObject\u PreviewKeyDown);
}
受保护的覆盖无效取消初始化()
{
if(this.AssociatedObject!=null)
{
this.AssociatedObject.PreviewKeyDown-=新的KeyEventHandler(AssociatedObject\u PreviewKeyDown);
}
}
void associated object_PreviewKeyDown(对象发送方,KeyEventArgs e)
{
//如果要将命令参数传递给CanExecute,则需要添加另一个要绑定的依赖项属性
if(TabCommand!=null&&e.Key==Key.Tab&&TabCommand.CanExecute(null))
{
TabCommand.Execute(null);
}
}
XAML:
<ListBox Grid.Row="1" KeyboardNavigation.TabNavigation="Continue" ItemsSource="{Binding Path=OrderLines, Mode=OneWay}"
ItemTemplate="{DynamicResource LineTemplate}" SelectionMode="Extended">
<ListBox.ItemContainerStyle>
<Style TargetType="ListBoxItem">
<Setter Property="Margin" Value="0,5,0,5"/>
<Setter Property="BorderThickness" Value="1"/>
<Setter Property="Template" Value="{DynamicResource ListBoxItemTemplate}"/>
<Setter Property="IsEnabled" Value="{Binding Path=IsLocked, Converter={StaticResource NotBoolConverter}}"/>
<Setter Property="IsSelected" Value="{Binding Path=IsSelected}"/>
</Style>
</ListBox.ItemContainerStyle>
</ListBox>
<TextBox Grid.Column="9" Grid.Row="3" Text="{Binding Path=SellPriceOverride, UpdateSourceTrigger=PropertyChanged, Mode=TwoWay}" VerticalAlignment="Center" Margin="5,0" TabIndex="10">
<!--IF ANOTHER INTERACTIVE CONTROL IS ADDED PAST THIS ONE ON THE LINE, THIS COMMENT AND THE BEHAVIOR MUST BE MOVED TO THAT CONTROL INSTEAD-->
<e:Interaction.Behaviors>
<ZViewModels:TabOffCommandBehavior TabCommand="{Binding Path=DataContext.AddNewOrderLine, RelativeSource={RelativeSource Mode=FindAncestor, AncestorType=ListBox}}"/>
</e:Interaction.Behaviors>
</TextBox>
在“LineTemplate”内:
<ListBox Grid.Row="1" KeyboardNavigation.TabNavigation="Continue" ItemsSource="{Binding Path=OrderLines, Mode=OneWay}"
ItemTemplate="{DynamicResource LineTemplate}" SelectionMode="Extended">
<ListBox.ItemContainerStyle>
<Style TargetType="ListBoxItem">
<Setter Property="Margin" Value="0,5,0,5"/>
<Setter Property="BorderThickness" Value="1"/>
<Setter Property="Template" Value="{DynamicResource ListBoxItemTemplate}"/>
<Setter Property="IsEnabled" Value="{Binding Path=IsLocked, Converter={StaticResource NotBoolConverter}}"/>
<Setter Property="IsSelected" Value="{Binding Path=IsSelected}"/>
</Style>
</ListBox.ItemContainerStyle>
</ListBox>
<TextBox Grid.Column="9" Grid.Row="3" Text="{Binding Path=SellPriceOverride, UpdateSourceTrigger=PropertyChanged, Mode=TwoWay}" VerticalAlignment="Center" Margin="5,0" TabIndex="10">
<!--IF ANOTHER INTERACTIVE CONTROL IS ADDED PAST THIS ONE ON THE LINE, THIS COMMENT AND THE BEHAVIOR MUST BE MOVED TO THAT CONTROL INSTEAD-->
<e:Interaction.Behaviors>
<ZViewModels:TabOffCommandBehavior TabCommand="{Binding Path=DataContext.AddNewOrderLine, RelativeSource={RelativeSource Mode=FindAncestor, AncestorType=ListBox}}"/>
</e:Interaction.Behaviors>
</TextBox>
在命令的“Execute”方法中完成的唯一一件事是将一个对象添加到一个集合中,该集合是ListBox的ItemsSource
if (e.KeyCode == Keys.Tab)
在AddNewOrderLine方法中,尝试在添加的新项目上设置焦点。然后,为防止焦点更改,请修改以下代码:
void AssociatedObject_PreviewKeyDown(object sender, KeyEventArgs e)
{
// if you want to pass a command param to CanExecute, need to add another dependency property to bind to
if (TabCommand != null && e.Key == Key.Tab && TabCommand.CanExecute(null))
{
TabCommand.Execute(null);
e.Handled = true;
}
}
您是否在列表框中尝试过此选项:
<ListBox FocusManager.IsFocusScope="True" ... >
或者这个:
<ListBox KeyboardNavigation.DirectionalNavigation="Contained" ... >
或者两者都有?KeyCode是WinForms属性,是WinForms世界中的KeyDown处理程序的一部分。我正在处理WPF。另外,我已经在用e.Key==Key.Tab测试Tab了。你可以添加更多的代码吗?例如,我想看看你在哪里处理添加新控件。我明天可以,但这是在我的视图模型中完成的。当我调用com时另外,我在observablecollection中添加了一个项,它是列表框的项源。我还需要进一步研究它,但只需在您自己的TabCommand中处理焦点更改,并中断键关闭事件,可能就可以了。@TomGarske不确定“中断键关闭事件”是什么意思但是我按照您的要求添加了代码。我可能不理解这个问题,但是您是否尝试过设置事件e.Handled=true;然后手动将焦点设置在正确的对象上?您建议我如何将焦点设置到新项?我特别想要的是第一个输入字段(即文本框)在新的ListBoxItem上有焦点,但由于我正在通过命令和ViewModel中的ObservableCollection向ListBoxItem添加,因此我没有直接访问权限(我也不应该)可以创建一个自定义控件并将逻辑放入构造函数中——这样每次创建一个新的ListBox时,它都会为它的第一个项获取焦点。我想这是一个选项——将ListBoxItem DataTemplate转换为自定义控件——但如果不是这样的话,我宁愿不走这条路非常必要。我可能可以通过绑定来处理它……我在想一些关于viewmodel(ListBoxItem的datacontext)属性的事情,第一个文本框可以绑定到告诉它应该有焦点,然后