ListBox + WrapPanel箭头键导航

时间:2020-03-06 14:43:42  来源:igfitidea点击:

我正在尝试将其View属性设置为View.List来实现WinForms ListView的等效功能。在视觉上,以下工作正常。我的"列表框"中的文件名从上到下,然后换行到新列。

这是我正在使用的基本XAML:

<ListBox Name="thelist"
    IsSynchronizedWithCurrentItem="True"
    ItemsSource="{Binding}"
    ScrollViewer.VerticalScrollBarVisibility="Disabled">
    <ListBox.ItemsPanel>
        <ItemsPanelTemplate>
            <WrapPanel IsItemsHost="True"
                Orientation="Vertical" />
        </ItemsPanelTemplate>
    </ListBox.ItemsPanel>
</ListBox>

但是,默认箭头键导航不会自动换行。如果选择了列中的最后一项,则按向下箭头不会转到下一列的第一项。

我试图像这样处理KeyDown事件:

private void thelist_KeyDown( object sender, KeyEventArgs e ) {
    if ( object.ReferenceEquals( sender, thelist ) ) {
        if ( e.Key == Key.Down ) {
            e.Handled = true;
            thelist.Items.MoveCurrentToNext();
        }
        if ( e.Key == Key.Up ) {
            e.Handled = true;
            thelist.Items.MoveCurrentToPrevious();
        }
    }
}

这会产生我想要的列的最后一列到下一列的行为,而且在左右箭头处理方面也产生了奇怪的情况。每当它使用向上/向下箭头从一列换行到下一列/上一列时,随后一次使用向左或者向右箭头键会将选择移到发生换行之前选择的项目的左侧或者右侧。

假设列表中填充了字符串" 0001"到" 0100",每列有10个字符串。如果我使用向下箭头键从" 0010"转到" 0011",然后按向右箭头键,选择将移至" 0020",即" 0010"的右侧。如果选择了" 0011",并且我使用向上箭头键将选择移至" 0010",则按向右箭头键会将选择移至" 0021"(向" 0011"的右边移,并向左按箭头键将选择移至" 0001"。

任何帮助实现所需的列换行布局和箭头键导航将不胜感激。

(编辑移至我自己的答案,因为从技术上讲,这是一个答案。)

解决方案

事实证明,当它处理我对KeyDown事件的处理时,选择将更改为正确的项目,但重点是旧项目。

这是更新的KeyDown事件处理程序。由于绑定的缘故,Items集合返回的是我的实际项目,而不是ListBoxItem,所以我必须在末尾进行调用以获取实际的ListBoxItem,而我需要调用Focus()。通过交换" MoveCurrentToLast()"和" MoveCurrentToFirst()"的调用,可以实现从最后一项到第一项的包装,反之亦然。

private void thelist_KeyDown( object sender, KeyEventArgs e ) {
    if ( object.ReferenceEquals( sender, thelist ) ) {
        if ( thelist.Items.Count > 0 ) {
            switch ( e.Key ) {
                case Key.Down:
                    if ( !thelist.Items.MoveCurrentToNext() ) {
                        thelist.Items.MoveCurrentToLast();
                    }
                    break;

                case Key.Up:
                    if ( !thelist.Items.MoveCurrentToPrevious() ) {
                        thelist.Items.MoveCurrentToFirst();
                    }
                    break;

                default:
                    return;
            }

            e.Handled = true;
            ListBoxItem lbi = (ListBoxItem) thelist.ItemContainerGenerator.ContainerFromItem( thelist.SelectedItem );
            lbi.Focus();
        }
    }
}

我们应该能够在没有事件监听器的情况下使用KeyboardNavigation.DirectionalNavigation来执行此操作,例如

<ListBox Name="thelist"
         IsSynchronizedWithCurrentItem="True"
         ItemsSource="{Binding}"
         ScrollViewer.VerticalScrollBarVisibility="Disabled"
         KeyboardNavigation.DirectionalNavigation="Cycle">