Come disabilito la selezione in un ListBox?
Come disabilito la selezione in un ListBox?
Risposte:
ItemsControl
A meno che non siano necessari altri aspetti di ListBox
, è possibile utilizzare ItemsControl
invece. Posiziona gli oggetti in ItemsPanel
e non ha il concetto di selezione.
<ItemsControl ItemsSource="{Binding MyItems}" />
Per impostazione predefinita, ItemsControl
non supporta la virtualizzazione dei suoi elementi figlio. Se si dispone di molti elementi, la virtualizzazione può ridurre l'utilizzo della memoria e migliorare le prestazioni, nel qual caso è possibile utilizzare l'approccio 2 e definire lo stile ListBox
o aggiungere la virtualizzazione alla propriaItemsControl
.
ListBox
In alternativa, basta dare uno stile al ListBox in modo tale che la selezione non sia visibile.
<ListBox.Resources>
<Style TargetType="ListBoxItem">
<Style.Resources>
<!-- SelectedItem with focus -->
<SolidColorBrush x:Key="{x:Static SystemColors.HighlightBrushKey}"
Color="Transparent" />
<!-- SelectedItem without focus -->
<SolidColorBrush x:Key="{x:Static SystemColors.ControlBrushKey}"
Color="Transparent" />
<!-- SelectedItem text foreground -->
<SolidColorBrush x:Key="{x:Static SystemColors.HighlightTextBrushKey}"
Color="Black" />
</Style.Resources>
<Setter Property="FocusVisualStyle" Value="{x:Null}" />
</Style>
</ListBox.Resources>
ItemsControl
rimuoverà completamente qualsiasi concetto di selezione.
Ho trovato una soluzione molto semplice e diretta che funziona per me, spero che farebbe anche per te
<ListBox ItemsSource="{Items}">
<ListBox.ItemContainerStyle>
<Style TargetType="{x:Type ListBoxItem}">
<Setter Property="Focusable" Value="False"/>
</Style>
</ListBox.ItemContainerStyle>
</ListBox>
Focusable = "False"
!
<Setter Property="IsHitTestVisible" Value="False" />
È possibile passare a utilizzare un ItemsControl
invece di a ListBox
. Un ItemsControl
non ha il concetto di selezione, quindi non c'è nulla per spegnere.
ItemTemplate
.
Un'altra opzione da considerare è la disabilitazione di ListBoxItems. Questo può essere fatto impostando ItemContainerStyle come mostrato nello snippet seguente.
<ListBox ItemsSource="{Binding YourCollection}">
<ListBox.ItemContainerStyle>
<Style TargetType="ListBoxItem">
<Setter Property="IsEnabled" Value="False" />
</Style>
</ListBox.ItemContainerStyle>
</ListBox>
Se non si desidera che il testo sia grigio, è possibile specificare il colore disabilitato aggiungendo un pennello alle risorse dello stile con la seguente chiave: {x: Static SystemColors.GrayTextBrushKey}. L'altra soluzione sarebbe quella di sovrascrivere il modello di controllo ListBoxItem.
Funzionerà anche se ho la necessità di usare la casella di riepilogo invece di itemscontrol, ma sto solo visualizzando gli elementi che non dovrebbero essere selezionabili, io uso:
<ListBox.ItemContainerStyle>
<Style TargetType="ListBoxItem">
<Setter Property="IsHitTestVisible" Value="False" />
</Style>
</ListBox.ItemContainerStyle>
Abbastanza buone risposte qui, ma stavo cercando qualcosa di leggermente diverso: voglio una selezione, ma non voglio che venga mostrata (o mostrata in una questione diversa).
Le soluzioni sopra non hanno funzionato per me (completamente), quindi ho fatto qualcos'altro: ho usato un nuovo stile per la mia casella di riepilogo, che ridefinisce completamente i modelli:
<Style x:Key="PlainListBoxStyle" TargetType="ListBox">
<Setter Property="ItemContainerStyle">
<Setter.Value>
<Style TargetType="ListBoxItem">
<Setter Property="Template">
<Setter.Value>
<ControlTemplate TargetType="ListBoxItem">
<ContentPresenter />
</ControlTemplate>
</Setter.Value>
</Setter>
</Style>
</Setter.Value>
</Setter>
<Setter Property="Template">
<Setter.Value>
<ControlTemplate TargetType="{x:Type ListBox}">
<ItemsPresenter/>
</ControlTemplate>
</Setter.Value>
</Setter>
</Style>
A partire da quello, puoi facilmente aggiungere l'evidenziazione della tua selezione o lasciarla così se non ne vuoi affatto.
Mentre la risposta di @Drew Noakes è una soluzione rapida per la maggior parte dei casi, c'è un piccolo difetto che deriva dall'impostazione dei pennelli x: statici.
Quando si impostano i pennelli x: Static come suggerito, tutti i controlli figlio all'interno della casella di riepilogo erediteranno questo stile.
Ciò significa che, mentre funzionerà per disabilitare l'evidenziazione della voce della casella di riepilogo, ciò potrebbe comportare effetti indesiderati per i controlli figlio.
Ad esempio, se avessi un ComboBox nel tuo ListBoxItem, disabiliterebbe il mouse sull'evidenziazione all'interno del ComboBox.
Prendi invece in considerazione l'impostazione degli VisualState per gli eventi Selected, Unselected e MouseOver come descritto nella soluzione menzionata in questo thread di stackoverflow: Rimuovi Evidenzia controllo da ListBoxItem ma non controlli figlio .
-Frinny
Propongo ancora un'altra soluzione. Re-template semplicemente ListBoxItem
per essere nient'altro che un ContentPresenter
, in questo modo ...
<Style TargetType="{x:Type ListBoxItem}">
<Setter Property="Template">
<Setter.Value>
<ControlTemplate TargetType="{x:Type ListBoxItem}">
<ContentPresenter />
</ControlTemplate>
</Setter.Value>
</Setter>
</Style>
Le mie ragioni per questo approccio sono le seguenti:
Nel mio caso, non voglio disabilitare l'interazione dell'utente con i contenuti del mio, ListBoxItems
quindi la soluzione da impostare IsEnabled
non funzionerà per me.
L'altra soluzione che tenta di ridisegnare lo stile ListBoxItem
sovrascrivendo le proprietà relative al colore funziona solo per quelle istanze in cui si è certi che il modello utilizzi tali proprietà. Va bene per gli stili predefiniti, ma si rompe con stili personalizzati.
Le soluzioni che utilizzano ItemsControl
interrompono troppe altre cose in quanto ItemsControl
hanno un aspetto completamente diverso rispetto a uno standard ListBox
e non supportano la virtualizzazione, il che significa che devi riprogrammare ItemsPanel
comunque.
Quanto sopra non cambia l'aspetto predefinito di ListBox
, non disabilita gli elementi nei modelli di dati per il ListBox
, supporta la virtualizzazione di default e funziona indipendentemente da qualsiasi stile possa essere o non essere in uso nella tua app. È il principio KISS.
Nota: questa soluzione non disabilita la selezione tramite la navigazione da tastiera o facendo clic con il tasto destro (es. Tasti freccia seguiti da tasto spazio)
Tutte le risposte precedenti rimuovono completamente la selezione dell'abilità (nessuna commutazione in runtime) o semplicemente rimuovono l'effetto visivo, ma non la selezione.
Ma cosa succede se si desidera essere in grado di selezionare e mostrare la selezione per codice, ma non per input dell'utente? Potresti voler "bloccare" la selezione dell'utente senza disabilitare l'intera Listbox?
La soluzione è quella di avvolgere l'intero ItemsContentTemplate in un pulsante che non ha chrome visivo. La dimensione del pulsante deve essere uguale alla dimensione dell'articolo, quindi è completamente coperta. Ora usa la proprietà IsEnabled del pulsante:
Abilita il pulsante per "bloccare" lo stato di selezione dell'elemento. Questo funziona perché il pulsante abilitato mangia tutti gli eventi del mouse prima che si spostino nel ListboxItem-Eventhandler. ItemsDataTemplate riceverà comunque MouseEvents perché fa parte del contenuto dei pulsanti.
Disabilitare il pulsante per abilitare la modifica della selezione facendo clic.
<Style x:Key="LedCT" TargetType="{x:Type ListBoxItem}">
<Setter Property="Template">
<Setter.Value>
<ControlTemplate TargetType="{x:Type ListBoxItem}">
<Button IsEnabled="{Binding IsSelectable, Converter={StaticResource BoolOppositeConverter}}" Template="{DynamicResource InvisibleButton}">
<ContentPresenter />
</Button>
</ControlTemplate>
</Setter.Value>
</Setter>
</Style>
<ControlTemplate x:Key="InvisibleButton" TargetType="{x:Type Button}">
<ContentPresenter/>
</ControlTemplate>
dartrax
Forse hai bisogno solo della funzionalità di ItemsControl? Non consente la selezione:
<ItemsControl ItemsSource="{Binding Prop1}" ItemTemplate="{StaticResource DataItemsTemplate}" />
Una semplice correzione che funziona su Windows Phone, ad esempio, è la selezione che imposta l'elemento selezionato su null:
<ListBox SelectionChanged="ListBox_SelectionChanged">
E nel codice dietro:
private void ListBox_SelectionChanged(object sender, System.Windows.Controls.SelectionChangedEventArgs e)
{
(sender as ListBox).SelectedItem = null;
}
Ho trovato un modo perfetto.
Impostare ListBox IsHitTestVisible su false in modo che l'utente non possa passare con il mouse o scorrere verso il basso o verso l'alto.
Capture PreviewGotKeyboardFocus e.Handled = true in modo che l'utente possa selezionare l'elemento tramite la tastiera Tab, Freccia su, Freccia giù.
In questo modo vantaggio:
Xmal
<ListBox Name="StudentsListBox" ItemsSource="{Binding Students}" ScrollViewer.VerticalScrollBarVisibility="Disabled" ScrollViewer.HorizontalScrollBarVisibility="Disabled" BorderThickness="0" Background="Transparent" IsHitTestVisible="False" PreviewGotKeyboardFocus="StudentsListBox_PreviewGotKeyboardFocus">
<ListBox.ItemContainerStyle>
<Style TargetType="{x:Type ListBoxItem}">
<Setter Property="Padding" Value="0"/>
<Setter Property="Margin" Value="0"/>
<Setter Property="Template">
<Setter.Value>
<ControlTemplate TargetType="{x:Type ListBoxItem}">
<Border x:Name="Bd">
<ContentPresenter/>
</Border>
<ControlTemplate.Triggers>
<MultiTrigger>
<MultiTrigger.Conditions>
<Condition Property="Selector.IsSelectionActive" Value="False" />
<Condition Property="IsSelected" Value="True" />
</MultiTrigger.Conditions>
<Setter TargetName="Bd" Property="Background" Value="Yellow" />
<Setter TargetName="Bd" Property="BorderBrush" Value="Transparent" />
</MultiTrigger>
</ControlTemplate.Triggers>
</ControlTemplate>
</Setter.Value>
</Setter>
</Style>
</ListBox.ItemContainerStyle>
<ItemsControl.ItemTemplate>
<DataTemplate>
<Grid Margin="0,0,0,0">
<Grid.ColumnDefinitions>
<ColumnDefinition Width="Auto" />
<ColumnDefinition Width="*" />
</Grid.ColumnDefinitions>
<TextBlock Grid.Column="0" Name="GradeBlock" Text="{Binding Grade}" FontSize="12" Margin="0,0,5,0"/>
<TextBlock Grid.Column="1" Name="NameTextBlock" Text="{Binding Name}" FontSize="12" TextWrapping="Wrap"/>
</Grid>
</DataTemplate>
</ItemsControl.ItemTemplate>
</ListBox>
codice
private void StudentsListBox_PreviewGotKeyboardFocus(object sender, KeyboardFocusChangedEventArgs e)
{
e.Handled = true;
}
Per me la migliore soluzione è:
<ListBox.ItemContainerStyle>
<Style TargetType="{x:Type ListBoxItem}">
<Setter Property="Focusable" Value="True"/>
<Setter Property="IsHitTestVisible" Value="False" />
</Style>
</ListBox.ItemContainerStyle>
IsEnabled = false
Per disabilitare una o più opzioni nella casella di riepilogo / elenco a discesa, è possibile aggiungere l'attributo "disabilitato" come mostrato di seguito. Ciò impedisce all'utente di selezionare questa opzione e si ottiene una sovrapposizione grigia.
ListItem item = new ListItem(yourvalue, yourkey);
item.Attributes.Add("disabled","disabled");
lb1.Items.Add(item);