Navigazione tasto freccia ListBox + WrapPanel
Domanda
Sto cercando di ottenere l'equivalente di un ListView
con la sua proprietà View
impostata su View.List
. Visivamente, quanto segue funziona bene. I nomi dei file nella mia Listbox
vanno dall'alto verso il basso, quindi vanno a capo in una nuova colonna.
Ecco l'XAML di base con cui sto lavorando:
<ListBox Name="thelist"
IsSynchronizedWithCurrentItem="True"
ItemsSource="{Binding}"
ScrollViewer.VerticalScrollBarVisibility="Disabled">
<ListBox.ItemsPanel>
<ItemsPanelTemplate>
<WrapPanel IsItemsHost="True"
Orientation="Vertical" />
</ItemsPanelTemplate>
</ListBox.ItemsPanel>
</ListBox>
Tuttavia, la navigazione del tasto freccia predefinito non va a capo. Se viene selezionato l'ultimo elemento in una colonna, premendo la freccia giù non si passa al primo elemento della colonna successiva.
Ho provato a gestire l'evento KeyDown
in questo modo:
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();
}
}
}
Questo produce il comportamento dall'ultima colonna alla prima colonna successiva che desideravo, ma produce anche una stranezza nella gestione delle frecce sinistra e destra. Ogni volta che passa da una colonna alla successiva / precedente usando le frecce su / giù, un singolo uso successivo del tasto freccia sinistra o destra sposta la selezione a sinistra o a destra dell'elemento che è stato selezionato appena prima dell'avvolgimento.
Supponi che l'elenco sia pieno di stringhe " 0001 " attraverso " 0100 " con 10 stringhe per colonna. Se uso il tasto freccia giù per passare da " 0010 " su "0011", quindi premere il tasto freccia destra, la selezione si sposta su "0020", appena a destra di "0010". Se "0011" è selezionato e utilizzo il tasto freccia su per spostare la selezione su " 0010 " ;, quindi una pressione dei tasti freccia destra sposta la selezione su " 0021 " (a destra di " 0011 " ;, e una pressione del tasto freccia sinistra sposta la selezione su " 0001 " ;.
Qualsiasi aiuto per ottenere il layout desiderato di avvolgimento di colonna e la navigazione con i tasti freccia sarebbe apprezzato.
(Le modifiche sono passate alla mia risposta, dal momento che tecnicamente è una risposta.)
Soluzione
Si scopre che quando si avvolge nella mia gestione dell'evento KeyDown
, la selezione cambia nell'elemento corretto, ma il focus è sull'elemento vecchio.
Ecco il gestore degli eventi KeyDown
aggiornato. A causa di Binding, la raccolta Items
restituisce i miei articoli effettivi anziché ListBoxItem
, quindi devo fare una chiamata verso la fine per ottenere il ListBoxItem Devo chiamare
Focus ()
su. Il passaggio dall'ultimo elemento al primo e viceversa può essere ottenuto scambiando le chiamate di MoveCurrentToLast ()
e 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();
}
}
}
Altri suggerimenti
Dovresti essere in grado di farlo senza il listener di eventi utilizzando KeyboardNavigation.DirectionalNavigation, ad esempio
<ListBox Name="thelist"
IsSynchronizedWithCurrentItem="True"
ItemsSource="{Binding}"
ScrollViewer.VerticalScrollBarVisibility="Disabled"
KeyboardNavigation.DirectionalNavigation="Cycle">