WPF ListView disattiva la selezione


119

Ho un semplice ListView WPF e una semplice domanda:

È possibile disattivare la selezione, quindi quando l'utente fa clic sulla riga, la riga non viene evidenziata?

Visualizzazione elenco

Vorrei che la riga 1 assomigliasse alla riga 0 quando si fa clic.

Possibilmente correlato: posso modellare l'aspetto del passaggio del mouse / selezione? Per esempio. per sostituire l'aspetto sfumato blu al passaggio del mouse (riga 3) con un colore solido personalizzato. Ho trovato questo e questo , purtroppo non aiutando.

(Anche ottenere lo stesso risultato senza utilizzare ListView è accettabile. Mi piacerebbe solo essere in grado di utilizzare lo scorrimento logico e la virtualizzazione dell'interfaccia utente come fa ListView)

Il codice XAML per ListView è:

<ListView Height="280" Name="listView">
    <ListView.Resources>
        <!-- attempt to override selection color -->
        <SolidColorBrush x:Key="{x:Static SystemColors.HighlightColorKey}"
                         Color="Green" />
    </ListView.Resources>
    <ListView.View>
        <GridView>
            <GridView.Columns>
                <GridViewColumn Header="Name" DisplayMemberBinding="{Binding Name}" />
                <!-- more columns -->
            </GridView.Columns>
        </GridView>
     </ListView.View>
</ListView>

Non ho mai usato un ListView in WPF prima, ma sono sicuro che esiste una sorta di proprietà IsEnabled che, se impostata su false, disabiliterebbe l'intero controllo e probabilmente otterrebbe ciò che stai cercando, ma sono non sicuro al 100%.
James McConnell

Ciao, sì, c'è una proprietà IsEnabled, che può disabilitare l'intero ListView. Ho bisogno che ListView funzioni normalmente, ma non visualizzare la selezione.
Martin Konicek

Risposte:


135

Secondo il commento di Martin Konicek, per disabilitare completamente la selezione degli elementi nel modo più semplice:

<ListView>
    <ListView.ItemContainerStyle>
        <Style TargetType="ListViewItem">
            <Setter Property="Focusable" Value="false"/>
        </Style>
    </ListView.ItemContainerStyle>
    ...
</ListView>

Tuttavia, se hai ancora bisogno della funzionalità di ListView, come la possibilità di selezionare un elemento, puoi disabilitare visivamente lo stile dell'elemento selezionato in questo modo:

Puoi farlo in diversi modi, dalla modifica del ControlTemplate di ListViewItem all'impostazione di uno stile (molto più semplice). È possibile creare uno stile per ListViewItems utilizzando ItemContainerStyle e "disattivare" il pennello per lo sfondo e il bordo quando viene selezionato.

<ListView>
    <ListView.ItemContainerStyle>
        <Style TargetType="{x:Type ListViewItem}">
            <Style.Triggers>
                <Trigger Property="IsSelected"
                         Value="True">
                    <Setter Property="Background"
                            Value="{x:Null}" />
                    <Setter Property="BorderBrush"
                            Value="{x:Null}" />
                </Trigger>
            </Style.Triggers>
        </Style>
    </ListView.ItemContainerStyle>
    ...
</ListView>

Inoltre, a meno che tu non abbia qualche altro modo per avvisare l'utente quando l'elemento è selezionato (o solo per il test), puoi aggiungere una colonna per rappresentare il valore:

<GridViewColumn Header="IsSelected"
                DisplayMemberBinding="{Binding RelativeSource={RelativeSource Mode=FindAncestor, AncestorType={x:Type ListViewItem}}, Path=IsSelected}" />

2
Non ho visto la parte correlata, ma puoi fare la stessa cosa, impostando lo sfondo e il bordo come preferisci sulla proprietà IsMouseOver.
rmoore

88
L'ho risolto ancora meglio ora - <Setter Property = "Focusable" Value = "false" /> disabilita completamente la selezione della riga.
Martin Konicek

8
Ahh, pensavo intendessi semplicemente disattivare la selezione visivamente. Se non vuoi che siano selezionati affatto, potresti voler dare un'occhiata all'uso di un ItemsControl (poiché puoi ancora impostare gli elementi selezionati tramite il codice se non sono attivabili), anche se per ottenere l'aspetto Grid tu Dovrai fare qualcosa del genere: manicprogrammer.com/cs/blogs/… Inoltre, se non l'hai ancora fatto, potresti dare un'occhiata al libro WPF Unleashed, in quanto fornisce un'ottima introduzione a WPF e XAML.
rmoore

2
@MartinKonicek so che è un vecchio post ma il tuo commento più votato dovrebbe essere una risposta;)
WiiMaxx,

1
@MartinKonicek ho dovuto aggiungere in BasedOn="{StaticResource {x:Type ListViewItem}}"modo che non sovrascriva il resto dei miei stili di griglia, ma penso anche che dovresti rendere il tuo commento la risposta accettata
JumpingJezza

31

La risposta di Moore non funziona e la pagina qui:

Specifica del colore della selezione, dell'allineamento del contenuto e del colore di sfondo per gli elementi in un ListBox

spiega perché non può funzionare.

Se il tuo listview contiene solo testo di base, il modo più semplice per risolvere il problema è usare pennelli trasparenti.

<Window.Resources>
  <Style TargetType="{x:Type ListViewItem}">
    <Style.Resources>
      <SolidColorBrush x:Key="{x:Static SystemColors.HighlightBrushKey}" Color="#00000000"/>
      <SolidColorBrush x:Key="{x:Static SystemColors.ControlBrushKey}" Color="#00000000"/>
    </Style.Resources>
  </Style>
</Window.Resources>

Ciò produrrà risultati indesiderabili se le celle della listview contengono controlli come le caselle combinate, poiché cambia anche il loro colore. Per risolvere questo problema, è necessario ridefinire il modello del controllo.

  <Window.Resources>
    <Style TargetType="{x:Type ListViewItem}">
      <Setter Property="Template">
        <Setter.Value>
          <ControlTemplate TargetType="{x:Type ListViewItem}">
            <Border SnapsToDevicePixels="True" 
                    x:Name="Bd" 
                    Background="{TemplateBinding Background}" 
                    BorderBrush="{TemplateBinding BorderBrush}" 
                    BorderThickness="{TemplateBinding BorderThickness}" 
                    Padding="{TemplateBinding Padding}">
              <GridViewRowPresenter SnapsToDevicePixels="{TemplateBinding SnapsToDevicePixels}" 
                                    VerticalAlignment="{TemplateBinding VerticalContentAlignment}" 
                                    Columns="{TemplateBinding GridView.ColumnCollection}" 
                                    Content="{TemplateBinding Content}"/>
            </Border>
            <ControlTemplate.Triggers>
              <Trigger Property="IsEnabled" 
                       Value="False">
                <Setter Property="Foreground" 
                        Value="{DynamicResource {x:Static SystemColors.GrayTextBrushKey}}"/>
              </Trigger>
            </ControlTemplate.Triggers>
          </ControlTemplate>
        </Setter.Value>
      </Setter>
    </Style>
  </Window.Resources>

14
Questo fa sparire tutti i miei articoli nel mio ListView
Chuck Savage

18

Impostare lo stile di ogni ListViewItem in modo che Focusable sia impostato su false.

<ListView ItemsSource="{Binding Test}" >
    <ListView.ItemContainerStyle>
        <Style TargetType="{x:Type ListViewItem}">
            <Setter Property="Focusable" Value="False"/>
        </Style>
    </ListView.ItemContainerStyle>
</ListView>

4
Semplice ed efficiente. E in realtà fa ciò che viene richiesto: disattiva la selezione invece di nasconderla. Questa è la migliore risposta.
Fumidu

13

Ecco il modello predefinito per ListViewItem da Blend:

Modello ListViewItem predefinito:

        <Setter Property="Template">
            <Setter.Value>
                <ControlTemplate TargetType="{x:Type ListViewItem}">
                    <Border x:Name="Bd" BorderBrush="{TemplateBinding BorderBrush}" BorderThickness="{TemplateBinding BorderThickness}" Background="{TemplateBinding Background}" Padding="{TemplateBinding Padding}" SnapsToDevicePixels="true">
                        <ContentPresenter HorizontalAlignment="{TemplateBinding HorizontalContentAlignment}" SnapsToDevicePixels="{TemplateBinding SnapsToDevicePixels}" VerticalAlignment="{TemplateBinding VerticalContentAlignment}"/>
                    </Border>
                    <ControlTemplate.Triggers>
                        <Trigger Property="IsSelected" Value="true">
                            <Setter Property="Background" TargetName="Bd" Value="{DynamicResource {x:Static SystemColors.HighlightBrushKey}}"/>
                            <Setter Property="Foreground" Value="{DynamicResource {x:Static SystemColors.HighlightTextBrushKey}}"/>
                        </Trigger>
                        <MultiTrigger>
                            <MultiTrigger.Conditions>
                                <Condition Property="IsSelected" Value="true"/>
                                <Condition Property="Selector.IsSelectionActive" Value="false"/>
                            </MultiTrigger.Conditions>
                            <Setter Property="Background" TargetName="Bd" Value="{DynamicResource {x:Static SystemColors.InactiveSelectionHighlightBrushKey}}"/>
                            <Setter Property="Foreground" Value="{DynamicResource {x:Static SystemColors.InactiveSelectionHighlightTextBrushKey}}"/>
                        </MultiTrigger>
                        <Trigger Property="IsEnabled" Value="false">
                            <Setter Property="Foreground" Value="{DynamicResource {x:Static SystemColors.GrayTextBrushKey}}"/>
                        </Trigger>
                    </ControlTemplate.Triggers>
                </ControlTemplate>
            </Setter.Value>
        </Setter>

Basta rimuovere IsSelected Trigger e IsSelected / IsSelectionActive MultiTrigger, aggiungendo il codice seguente al tuo stile per sostituire il modello predefinito e non ci sarà alcun cambiamento visivo quando selezionato.

Soluzione per disattivare le modifiche visive della proprietà IsSelected:

    <Setter Property="Template">
        <Setter.Value>
            <ControlTemplate TargetType="{x:Type ListViewItem}">
                <Border x:Name="Bd" BorderBrush="{TemplateBinding BorderBrush}" BorderThickness="{TemplateBinding BorderThickness}" Background="{TemplateBinding Background}" Padding="{TemplateBinding Padding}" SnapsToDevicePixels="true">
                    <ContentPresenter HorizontalAlignment="{TemplateBinding HorizontalContentAlignment}" SnapsToDevicePixels="{TemplateBinding SnapsToDevicePixels}" VerticalAlignment="{TemplateBinding VerticalContentAlignment}"/>
                </Border>
                <ControlTemplate.Triggers>
                    <Trigger Property="IsEnabled" Value="false">
                        <Setter Property="Foreground" Value="{DynamicResource {x:Static SystemColors.GrayTextBrushKey}}"/>
                    </Trigger>
                </ControlTemplate.Triggers>
            </ControlTemplate>
        </Setter.Value>
    </Setter>


8

Oltre alla soluzione sopra ... utilizzerei un MultiTrigger per consentire ai punti salienti di MouseOver di continuare a funzionare dopo la selezione in modo tale che lo stile del tuo ListViewItem sarà:

        <ListView.ItemContainerStyle>
            <Style TargetType="ListViewItem">
                <Style.Triggers>
                    <MultiTrigger>
                        <MultiTrigger.Conditions>
                            <Condition Property="IsSelected" Value="True" />
                            <Condition Property="IsMouseOver" Value="False" />
                        </MultiTrigger.Conditions>
                        <MultiTrigger.Setters>
                            <Setter Property="Background" Value="{x:Null}" />
                            <Setter Property="BorderBrush" Value="{x:Null}" />
                        </MultiTrigger.Setters>
                    </MultiTrigger>
                </Style.Triggers>
            </Style>
        </ListView.ItemContainerStyle>

6

Ok, un po 'tardi per il gioco, ma nessuna di queste soluzioni ha fatto quello che stavo cercando di fare. Queste soluzioni hanno un paio di problemi

  1. Disabilita ListViewItem, che rovina gli stili e disabilita tutti i controlli figli
  2. Rimuovi dallo stack di hit test, ovvero i controlli secondari non ricevono mai un passaggio del mouse o un clic
  3. Rendilo non focalizzabile, questo semplicemente non ha funzionato per me?

Volevo un ListView con le intestazioni di raggruppamento e ogni ListViewItem dovrebbe essere solo "informativo" senza selezione o passare il mouse sopra, ma ListViewItem ha un pulsante in esso che voglio essere cliccabile e avere il passaggio del mouse.

Quindi, in realtà quello che voglio è che ListViewItem non sia affatto un ListViewItem, quindi ho superato il ControlTemplate di ListViewItem e l'ho appena reso un semplice ContentControl.

<ListView.ItemContainerStyle>
    <Style TargetType="ListViewItem">
        <Setter Property="Template">
            <Setter.Value>
                <ControlTemplate>
                    <ContentControl Content="{Binding Content, RelativeSource={RelativeSource TemplatedParent}}"/>
                </ControlTemplate>
            </Setter.Value>
         </Setter>
     </Style>
</ListView.ItemContainerStyle>

5

Una delle proprietà del listview è IsHitTestVisible. Deselezionalo.


Semplice ed efficace, risolve anche il mio problema con ScrollViewer avvolto in una visualizzazione elenco.
Brian Ng

1
Ho un modello di pulsante all'interno del modello di elemento listview. se deseleziona IsHitTestVisibleil pulsante non è possibile cliccare. Si comporta comeIsEnabled = false;
Luiey

1

Questo è per altri che potrebbero incontrare i seguenti requisiti:

  1. Sostituisci completamente l'indicazione visiva di "selezionato" (es. Usa un qualche tipo di forma), oltre a cambiare semplicemente il colore dell'evidenziazione standard
  2. Includere questa indicazione selezionata nel DataTemplate insieme alle altre rappresentazioni visive del modello, ma,
  3. Non si desidera dover aggiungere una proprietà "IsSelectedItem" alla classe del modello ed essere gravato dalla manipolazione manuale di tale proprietà su tutti gli oggetti del modello.
  4. Richiede che gli elementi siano selezionabili in ListView
  5. Inoltre vorrebbe sostituire la rappresentazione visiva di IsMouseOver

Se sei come me (usando WPF con .NET 4.5) e hai scoperto che le soluzioni che coinvolgono i trigger di stile semplicemente non funzionavano, ecco la mia soluzione:

Sostituisci ControlTemplate di ListViewItem in uno stile:

<ListView ItemsSource="{Binding MyStrings}" ItemTemplate="{StaticResource dtStrings}">
        <ListView.ItemContainerStyle>
            <Style TargetType="ListViewItem">
                <Setter Property="Template">
                    <Setter.Value>
                        <ControlTemplate TargetType="ListViewItem">
                            <ContentPresenter/>
                        </ControlTemplate>
                    </Setter.Value>
                </Setter>
            </Style>
        </ListView.ItemContainerStyle>
    </ListView>

..E il DataTemplate:

<DataTemplate x:Key="dtStrings">
        <Border Background="LightCoral" Width="80" Height="24" Margin="1">
            <Grid >
                <Border Grid.ColumnSpan="2" Background="#88FF0000" Visibility="{Binding RelativeSource={RelativeSource AncestorType=ListViewItem}, Path=IsMouseOver, Converter={StaticResource conBoolToVisibilityTrueIsVisibleFalseIsCollapsed}}"/>
                <Rectangle Grid.Column="0" Fill="Lime" Width="10" HorizontalAlignment="Left" Visibility="{Binding RelativeSource={RelativeSource AncestorType=ListViewItem}, Path=IsSelected, Converter={StaticResource conBoolToVisibilityTrueIsVisibleFalseIsCollapsed}}" />
                <TextBlock Grid.Column="1" Text="{Binding}" HorizontalAlignment="Center" VerticalAlignment="Center" Foreground="White" />
            </Grid>
        </Border>
    </DataTemplate>

Risultati in questo in fase di esecuzione (l'elemento "B" è selezionato, l'elemento "D" ha il mouse):

Aspetto ListView


1

Usa il codice qui sotto:

   <ListView.ItemContainerStyle>
          <Style TargetType="{x:Type ListViewItem}">
           <Setter Property="Background" Value="Transparent`enter code here`" />
             <Setter Property="Template">
               <Setter.Value>
                 <ControlTemplate TargetType="{x:Type ListViewItem}">
                   <ContentPresenter />
                 </ControlTemplate>
               </Setter.Value>
             </Setter>
          </Style>
   </ListView.ItemContainerStyle>

0

Il codice sottostante disabilita la selezione della riga ListViewItem e consente anche di aggiungere padding, margine ecc.

<ListView.ItemContainerStyle>                                                                              
   <Style TargetType="ListViewItem">                                                                                      
       <Setter Property="Template">                                                                                            
         <Setter.Value>                                                                                             
           <ControlTemplate TargetType="{x:Type ListViewItem}">                                                                                                    
              <ListViewItem Padding="0" Margin="0">                                                                                                        
                  <ContentPresenter />
              </ListViewItem>
           </ControlTemplate>                                                          
         </Setter.Value>                                                                                       
         </Setter>
      </Style>                                                                      
  </ListView.ItemContainerStyle> 

0

Di seguito il codice disabilita Focus su ListViewItem

<ListView.ItemContainerStyle>
<Style TargetType="{x:Type ListViewItem}">
    <Setter Property="Background" Value="Transparent" />
    <Setter Property="Template">
        <Setter.Value>
            <ControlTemplate TargetType="{x:Type ListViewItem}">
                <ContentPresenter />
            </ControlTemplate>
        </Setter.Value>
    </Setter>
</Style>

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.