I'm trying to achieve the equivalent of a WinForms ListView
with its View
property set to View.List
. Visually, the following works fine. The file names in my Listbox
go from top to bottom, and then wrap to a new column.
Here's the basic XAML I'm working with:
<ListBox Name="thelist"
IsSynchronizedWithCurrentItem="True"
ItemsSource="{Binding}"
ScrollViewer.VerticalScrollBarVisibility="Disabled">
<ListBox.ItemsPanel>
<ItemsPanelTemplate>
<WrapPanel IsItemsHost="True"
Orientation="Vertical" />
</ItemsPanelTemplate>
</ListBox.ItemsPanel>
</ListBox>
However, default arrow key navigation does not wrap. If the last item in a column is selected, pressing the down arrow does not go to the first item of the next column.
I tried handling the KeyDown
event like this:
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();
}
}
}
This produces the last-in-column to first-in-next-column behavior that I wanted, but also produces an oddity in the left and right arrow handling. Any time it wraps from one column to the next/previous using the up/down arrows, a single subsequent use of the left or right arrow key moves the selection to the left or right of the item that was selected just before the wrap occured.
Assume the list is filled with strings "0001" through "0100" with 10 strings per column. If I use the down arrow key to go from "0010" to "0011", then press the right arrow key, selection moves to "0020", just to the right of "0010". If "0011" is selected and I use the up arrow key to move selection to "0010", then a press of the right arrow keys moves selection to "0021" (to the right of "0011", and a press of the left arrow key moves selection to "0001".
Any help achieving the desired column-wrap layout and arrow key navigation would be appreciated.
(Edits moved to my own answer, since it technically is an answer.)
It turns out that when it wraps around in my handling of the
KeyDown
event, selection changes to the correct item, but focus is on the old item.Here is the updated
KeyDown
eventhandler. Because of Binding, theItems
collection returns my actual items rather thanListBoxItem
s, so I have to do a call near the end to get the actualListBoxItem
I need to callFocus()
on. Wrapping from last item to first and vice-versa can be achieved by swapping the calls ofMoveCurrentToLast()
andMoveCurrentToFirst()
.You should be able to do it without the event listener using KeyboardNavigation.DirectionalNavigation, e.g.