WPF ListView wyłącz wybór

119

Mam prosty ListView WPF i proste pytanie:

Czy można wyłączyć zaznaczanie, aby po kliknięciu wiersza przez użytkownika wiersz nie był podświetlony?

ListView

Chciałbym, aby po kliknięciu wiersz 1 wyglądał jak wiersz 0.

Ewentualnie powiązane: czy mogę zmienić wygląd wskaźnika najechania / zaznaczenia? Na przykład. aby zastąpić niebieski wygląd gradientu po najechaniu kursorem (linia 3) na niestandardowy jednolity kolor. Znalazłem to i to niestety nie pomaga.

(Osiągnięcie tego samego bez używania ListView jest również dopuszczalne. Chciałbym tylko móc używać przewijania logicznego i wirtualizacji interfejsu użytkownika, tak jak robi to ListView)

XAML dla ListView to:

<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>
Martin Konicek
źródło
Nigdy wcześniej nie korzystałem z ListView w WPF, ale jestem pewien, że istnieje jakaś właściwość IsEnabled, która, jeśli zostanie ustawiona na false, wyłączy całą kontrolkę i prawdopodobnie osiągnie to, czego szukasz, ale jestem nie jestem w 100% pewien.
James McConnell
Cześć, tak, istnieje właściwość IsEnabled, która może wyłączyć cały ListView. Potrzebuję jednak, aby ListView działał normalnie, po prostu nie wyświetlaj zaznaczenia.
Martin Konicek

Odpowiedzi:

135

Zgodnie z komentarzem Martina Konicka, aby w najprostszy sposób całkowicie wyłączyć selekcję pozycji:

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

Jeśli jednak nadal potrzebujesz funkcjonalności ListView, na przykład możliwości wybrania elementu, możesz wizualnie wyłączyć stylizację wybranego elementu, tak jak poniżej:

Możesz to zrobić na wiele sposobów, od zmiany ControlTemplate ListViewItem do po prostu ustawienia stylu (znacznie łatwiej). Możesz utworzyć styl dla ListViewItems przy użyciu ItemContainerStyle i „wyłączyć” pędzel tła i obramowania, gdy jest zaznaczony.

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

Ponadto, jeśli nie masz innego sposobu powiadamiania użytkownika o wybraniu elementu (lub tylko do testowania), możesz dodać kolumnę reprezentującą wartość:

<GridViewColumn Header="IsSelected"
                DisplayMemberBinding="{Binding RelativeSource={RelativeSource Mode=FindAncestor, AncestorType={x:Type ListViewItem}}, Path=IsSelected}" />
rmoore
źródło
2
Nie widziałem powiązanej części, ale możesz zrobić to samo, ustawiając tło i obramowanie, jak chcesz we właściwości IsMouseOver.
rmoore
88
Teraz rozwiązałem to jeszcze lepiej - <Setter Property = "Focusable" Value = "false" /> całkowicie wyłącza zaznaczanie wiersza.
Martin Konicek
8
Ach, myślałem, że chodziło ci o wizualne wyłączenie Zaznaczenia. Jeśli nie chcesz, aby były one w ogóle wybierane, możesz rzucić okiem na użycie ItemsControl (ponieważ nadal możesz ustawić wybrane elementy za pomocą kodu, jeśli nie są one aktywne), ale aby uzyskać wygląd siatki Będę musiał zrobić coś takiego: manicprogrammer.com/cs/blogs/ ... Ponadto, jeśli jeszcze tego nie zrobiłeś, możesz zajrzeć do książki WPF Unleashed, ponieważ stanowi ona świetne wprowadzenie do WPF i XAML.
rmoore
2
@MartinKonicek Wiem, że to stary post, ale Twój wysoko oceniony komentarz powinien być odpowiedzią;)
WiiMaxx
1
@MartinKonicek Musiałem to dodać, BasedOn="{StaticResource {x:Type ListViewItem}}"więc nie przesłaniało to reszty moich stylów siatki, ale myślę również, że Twój komentarz powinien być zaakceptowaną odpowiedzią
JumpingJezza
31

Odpowiedź Moore'a nie działa, a strona tutaj:

Określanie koloru zaznaczenia, wyrównania zawartości i koloru tła dla elementów w ListBox

wyjaśnia, dlaczego nie może działać.

Jeśli widok listy zawiera tylko tekst podstawowy, najprostszym sposobem rozwiązania problemu jest użycie przezroczystych pędzli.

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

Spowoduje to niepożądane wyniki, jeśli komórki widoku listy zawierają kontrolki, takie jak komboksy, ponieważ zmienia to również ich kolor. Aby rozwiązać ten problem, musisz ponownie zdefiniować szablon kontrolki.

  <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>
Mark Markindale
źródło
14
To sprawia, że ​​wszystkie moje elementy w moim ListView znikają
Chuck Savage,
18

Ustaw styl każdego ListViewItem tak, aby Focusable był ustawiony na false.

<ListView ItemsSource="{Binding Test}" >
    <ListView.ItemContainerStyle>
        <Style TargetType="{x:Type ListViewItem}">
            <Setter Property="Focusable" Value="False"/>
        </Style>
    </ListView.ItemContainerStyle>
</ListView>
Hayley Guillou
źródło
4
Proste i wydajne. I faktycznie robi to, o co się go prosi: wyłącza zaznaczenie zamiast tylko go ukrywać. To najlepsza odpowiedź.
Fumidu
13

Oto domyślny szablon ListViewItem z programu Blend:

Domyślny szablon ListViewItem:

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

Po prostu usuń wyzwalacz IsSelected i IsSelected / IsSelectionActive MultiTrigger, dodając poniższy kod do swojego stylu w celu zastąpienia domyślnego szablonu, a po zaznaczeniu nie będzie żadnych zmian wizualnych.

Rozwiązanie umożliwiające wyłączenie zmian wizualnych właściwości 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>
Ben Wilde
źródło
12

Najłatwiejszy sposób, jaki znalazłem:

<Setter Property="Focusable" Value="false"/>
Martin Konicek
źródło
4
@Mutex To działa - musisz to jednak zastosować ListView.ItemContainerStyle!
Andreas Niedermair
8

W nawiązaniu do powyższego rozwiązania ... użyłbym MultiTriggera, aby umożliwić podświetleniom MouseOver kontynuowanie pracy po wybraniu, tak aby styl Twojego ListViewItem był następujący:

        <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>
Czerwony pies
źródło
6

Okej, trochę za późno na mecz, ale żadne z tych rozwiązań nie spełniło moich oczekiwań. Te rozwiązania mają kilka problemów

  1. Wyłącz ListViewItem, co skręca style i wyłącza wszystkie kontrolki podrzędne
  2. Usuń ze stosu testów trafień, tj. Kontrolki podrzędne nigdy nie są najeżdżane myszką ani nie klikają
  3. Spraw, aby nie można było ustawić ostrości, to po prostu nie działa dla mnie?

Chciałem ListView z nagłówkami grupowania, a każdy ListViewItem powinien być po prostu `` informacyjny '' bez zaznaczania lub najechania kursorem, ale ListViewItem ma w nim przycisk, który chcę, aby można go było kliknąć i najechać kursorem.

Tak więc naprawdę chcę, aby ListViewItem w ogóle nie był ListViewItem, więc przejechałem ControlTemplate ListViewItem i po prostu uczyniłem go prostym 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>
Bradley Burnside
źródło
5

Jedną z właściwości widoku listy jest IsHitTestVisible. Odznacz to.

Jacob Levertov
źródło
Prosty i skuteczny, rozwiązuje również mój problem za pomocą ScrollViewer zawiniętego w widok listy.
Brian Ng
1
Mam szablon przycisku wewnątrz szablonu elementu widoku listy. w przypadku odznaczenia IsHitTestVisibleprzycisku nie można kliknąć. To wygląda jakIsEnabled = false;
Luiey
1

To jest dla innych, którzy mogą napotkać następujące wymagania:

  1. Całkowicie zastąp wizualne oznaczenie „wybranego” (np. Użyj jakiegoś kształtu), poza zwykłą zmianą koloru standardowego podświetlenia
  2. Uwzględnij to wybrane wskazanie w DataTemplate wraz z innymi wizualnymi reprezentacjami modelu, ale
  3. Nie chcesz dodawać właściwości „IsSelectedItem” do swojej klasy modelu i być obciążonym ręcznym manipulowaniem tą właściwością na wszystkich obiektach modelu.
  4. Wymagaj, aby elementy mogły być wybierane w ListView
  5. Chciałbym również zastąpić wizualną reprezentację IsMouseOver

Jeśli jesteś podobny do mnie (korzystasz z WPF z .NET 4.5) i odkryłeś, że rozwiązania obejmujące wyzwalacze stylu po prostu nie działają, oto moje rozwiązanie:

Zastąp ControlTemplate ListViewItem w stylu:

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

.. I 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>

Wyniki tego w czasie wykonywania (pozycja „B” jest zaznaczona, pozycja „D” jest najechana kursorem):

Wygląd ListView

BCA
źródło
1

Użyj poniższego kodu:

   <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>
Jorge Freitas
źródło
0

Poniższy kod wyłącza wybór wiersza ListViewItem, a także pozwala na dodanie dopełnienia, marginesu itp.

<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> 
Saikat Chakraborty
źródło
0

Poniższy kod wyłącza Focus na 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>

mincasoft
źródło