Non esiste ListBox.SelectionMode = "None", esiste un altro modo per disabilitare la selezione in una casella di riepilogo?


189

Come disabilito la selezione in un ListBox?


1
Potresti fornire un esempio in cui è valido avere un ListBox che non puoi selezionare? Poiché il comportamento principale è selezionare elementi. Probabilmente sceglierei un altro modo per mostrarlo (questo non sono io che cerco di essere un critico, ma piuttosto un sincero interesse per dove ciò potrebbe accadere)
Marthin,

3
@Martin: ad esempio se si desidera trascinare il contenuto da una casella di riepilogo, in questo caso probabilmente non si è interessati a selezionare quell'elemento. INOLTRE: quando si trascina un elemento: l'elemento selezionato di cambiamenti listbox mentre si trascina all'interno della casella di riepilogo - vedere questo post stackoverflow.com/questions/7589142/...
DanielD

1
Credo che la ragione per cui Shimmy vuole usare ListBox è che il richiedente può rendere la casella di riepilogo selezionabile in qualche momento. Anche la domanda è preziosa per me. Supponi che stai costruendo un gioco di carte da gioco. Puoi selezionare una carta dalle tue carte, a volte, puoi selezionare più carte e altre volte, non puoi selezionarne nessuna.
Gqqnbig,

1
Inoltre, a volte hai 10 carte e solo 4 di esse sono selezionabili. Tra i 4, è possibile selezionare fino a 3.
Gqqnbig

1
@Marthin: quando hai un GridView in un ListBox. Le intestazioni di Gridview offrono molte funzionalità che non sono disponibili altrove. E hai controlli di modifica nelle celle del gridview.
Robin Davies,

Risposte:


264

Approccio 1 - ItemsControl

A meno che non siano necessari altri aspetti di ListBox, è possibile utilizzare ItemsControlinvece. Posiziona gli oggetti in ItemsPanele non ha il concetto di selezione.

<ItemsControl ItemsSource="{Binding MyItems}" />

Per impostazione predefinita, ItemsControlnon 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 ListBoxo aggiungere la virtualizzazione alla propriaItemsControl .

Approccio 2 - Styling 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>

24
no, cambierà solo l'effetto visivo, non l'attuale comportamento di selezione
Thomas Levesque,

8
Il mio primo suggerimento era di usare ItemsControl. Ti è mancato? :)
Drew Noakes,

5
Rileggendo nuovamente questi commenti, voglio sottolineare che il commento di @Thomas Levesque è vero solo per il secondo approccio che mostro. L'uso di plain ItemsControlrimuoverà completamente qualsiasi concetto di selezione.
Drew Noakes,

1
La soluzione ItemsControl rimuove dalla confezione il supporto per lo scorrimento (barra di scorrimento e rotellina del mouse).
MuiBienCarlota,

1
+1 per l'approccio 1 - ItemsControl. Se abbiamo una pagina enorme che dobbiamo scorrere, se l'utente passa il mouse su un ListBox, disabilita effettivamente MouseWheel poiché la casella di riepilogo acquisisce gli eventi MouseWheel. Ciò significa che l'utente è frustrato dal fatto che la rotellina del mouse utilizzata per scorrere l'intera pagina smetterà di funzionare in modo casuale, a seconda che il mouse si trovi su una casella di riepilogo o meno.
Contango,

159

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>

Penso che l'abbia affrontato abbastanza bene qui: asaddurrani.wordpress.com/tag/wpf-listbox-disable-selection
Sid

3
Questo è perfetto. impedisce l'elemento selezionato e altri controlli come i pulsanti funzionano ancora. esattamente quello che stavo cercando
Franck,

1
+1 per questo approccio. Se abbiamo una pagina enorme che dobbiamo scorrere, se l'utente passa il mouse su un ListBox, disabilita effettivamente MouseWheel poiché la casella di riepilogo acquisisce gli eventi MouseWheel. Ciò significa che l'utente è frustrato dal fatto che la rotellina del mouse utilizzata per scorrere l'intera pagina smetterà di funzionare in modo casuale, a seconda che il mouse si trovi su una casella di riepilogo o meno.
Contango,

Eccellente. Un approccio simile ha funzionato anche per me quando avevo bisogno di pulsanti sugli oggetti per non causare la selezione degli oggetti, ma solo se si faceva clic su un'altra area dell'oggetto. Basta impostare i pulsanti Focusable = "False"!
Jony Adamit,

1
Aggiungi questa proprietà aggiuntiva per rimuovere anche l'evidenziazione del passaggio del <Setter Property="IsHitTestVisible" Value="False" />
mouse

25

È possibile passare a utilizzare un ItemsControlinvece di a ListBox. Un ItemsControlnon ha il concetto di selezione, quindi non c'è nulla per spegnere.


2
Charming. Non ho mai saputo che potresti dichiarare direttamente ItemsControl, ho pensato che fosse virtuale (MustOverride), grazie !!!
Shimmy Weitzhandler,

Ma ItemsControl renderebbe comunque i miei articoli in una riga?
Chry Cheng,

@Chry sì, e inoltre puoi sempre impostare manualmente ItemTemplate.
Shimmy Weitzhandler,

2
Questo finisce per perdere troppe funzionalità, ad esempio lo scorrimento.
Jeff,

@Jeff è possibile avvolgere ItemsControl in ScrollViewer per ottenere lo scorrimento.
Wilka,

12

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.


Semplice e funzionante, grazie! Ed è applicabile anche su WP 8.1 Runtime.
Malutek,

8

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>

3

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.


2

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


2

Propongo ancora un'altra soluzione. Re-template semplicemente ListBoxItemper 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:

  1. Nel mio caso, non voglio disabilitare l'interazione dell'utente con i contenuti del mio, ListBoxItemsquindi la soluzione da impostare IsEnablednon funzionerà per me.

  2. L'altra soluzione che tenta di ridisegnare lo stile ListBoxItemsovrascrivendo 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.

  3. Le soluzioni che utilizzano ItemsControlinterrompono troppe altre cose in quanto ItemsControlhanno un aspetto completamente diverso rispetto a uno standard ListBoxe non supportano la virtualizzazione, il che significa che devi riprogrammare ItemsPanelcomunque.

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.


1

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


1

Forse hai bisogno solo della funzionalità di ItemsControl? Non consente la selezione:

<ItemsControl ItemsSource="{Binding Prop1}" ItemTemplate="{StaticResource DataItemsTemplate}" />

3
@Shimmy: è comune che le risposte banali siano simili. Non ci sono duplicazioni qui degne di alcuna bandiera. Se hai altre domande a riguardo, chiedi su Meta Stack Overflow .

0

È possibile posizionare un blocco di testo sopra la casella di riepilogo, non cambierà l'aspetto dell'applicazione e inoltre non consentirà di selezionare alcun elemento.


1
Tuttavia, dovrai comunque disabilitare la navigazione a schede.
Amanduh,

0

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

0

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:

  1. Gli elementi di ListBox in primo piano non diventano grigi.
  2. ListBox Background può essere impostato su Transparent

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

-1

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>


-3

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

Quella volta sei sballato e hai risposto a una domanda WPF con una soluzione ASP.NET.
Utilizzando il nostro sito, riconosci di aver letto e compreso le nostre Informativa sui cookie e Informativa sulla privacy.
Licensed under cc by-sa 3.0 with attribution required.