在Tab键上向ListBox添加新项目

时间:2012-05-14 18:45:15

标签: c# wpf listbox listboxitem attachedbehaviors

我有一个WPF ListBox,带有ListBox ItemTemplate的自定义DataTemplate(每个项目都有一组控件;即文本框和日期选择器)。我有一个附加到最后一个DatePicker的行为,它允许用户在PreviewKeyDown事件的事件处理程序中执行ICommand。

这个想法是用户将通过ListBoxItem中的控件进行TAB,当他们到达最后一个控件时,再次按TAB,新的ListBoxItem get被添加到ListBox中。然后焦点将移动到下一个ListBoxItem中的第一个控件。当ListBox中已有2个项目时,我的解决方案正常工作,并且您正在浏览第一个项目。如果ListBox中只有1个项目,并且您到达最后一个控件,则会添加新的ListBoxItem(如预期的那样),但焦点会从ListBox移动到下一个父控件。

就像调用行为代码并调用ICommand一样,但是TAB事件会继续,而不会等待添加新的ListBoxItem。

有什么建议吗?

我的行为(ZBehaviorBase只是一个允许“更好”清理的类):

public class TabOffCommandBehavior : ZBehaviorBase<FrameworkElement>
{
    public ICommand TabCommand
    {
        get { return (ICommand)GetValue(CommandProperty); }
        set { SetValue(CommandProperty, value); }
    }

    public static readonly DependencyProperty CommandProperty =
        DependencyProperty.Register("TabCommand", typeof(ICommand), typeof(TabOffCommandBehavior));

    protected override void Initialize()
    {
        this.AssociatedObject.PreviewKeyDown += new KeyEventHandler(AssociatedObject_PreviewKeyDown);
    }

    protected override void Uninitialize()
    {
        if (this.AssociatedObject != null)
        {
            this.AssociatedObject.PreviewKeyDown -= new KeyEventHandler(AssociatedObject_PreviewKeyDown);
        }
    }

    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);
        }
    }

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>

INSIDE“LineTemplate”:

<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>

在命令的“执行”方法中唯一完成的是将对象添加到集合中,该集合是ListBox的ItemsSource

3 个答案:

答案 0 :(得分:1)

在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;
    }
}

答案 1 :(得分:0)

尝试

if (e.KeyCode == Keys.Tab)

答案 2 :(得分:0)

你在ListBox上尝试过这个吗:

<ListBox FocusManager.IsFocusScope="True" ... >

或者这个:

<ListBox KeyboardNavigation.DirectionalNavigation="Contained" ... >

或两者兼而有之?