WPF ListView desligar a seleção

119

Eu tenho um ListView WPF simples e uma pergunta simples:

É possível desligar a seleção, para que quando o usuário clica na linha, a linha não seja destacada?

Exibição de lista

Gostaria que a linha 1 se parecesse com a linha 0 quando clicada.

Possivelmente relacionado: posso estilizar a aparência do foco / seleção? Por exemplo. para substituir a aparência do gradiente azul (linha 3) por uma cor sólida personalizada. Eu encontrei isso e isso , infelizmente não ajudando.

(Conseguir o mesmo sem usar ListView também é aceitável. Gostaria apenas de poder usar rolagem lógica e virtualização de IU como o ListView faz)

O XAML para 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>
Martin Konicek
fonte
Nunca usei um ListView no WPF antes, mas tenho certeza de que há algum tipo de propriedade IsEnabled que, se definida como false, desabilitaria todo o controle e provavelmente alcançaria o que você está procurando, mas estou não tenho 100% de certeza.
James McConnell
Oi, sim, há uma propriedade IsEnabled, que pode desativar todo o ListView. Eu preciso que o ListView esteja funcionando normalmente, apenas não exiba a seleção.
Martin Konicek

Respostas:

135

De acordo com o comentário de Martin Konicek, para desativar totalmente a seleção dos itens da maneira mais simples:

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

No entanto, se você ainda precisa da funcionalidade do ListView, como ser capaz de selecionar um item, você pode desativar visualmente o estilo do item selecionado da seguinte maneira:

Você pode fazer isso de várias maneiras, desde alterar o ControlTemplate do ListViewItem até apenas definir um estilo (muito mais fácil). Você pode criar um estilo para ListViewItems usando o ItemContainerStyle e 'desligar' o pincel de fundo e borda quando estiver selecionado.

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

Além disso, a menos que você tenha alguma outra maneira de notificar o usuário quando o item é selecionado (ou apenas para teste), você pode adicionar uma coluna para representar o valor:

<GridViewColumn Header="IsSelected"
                DisplayMemberBinding="{Binding RelativeSource={RelativeSource Mode=FindAncestor, AncestorType={x:Type ListViewItem}}, Path=IsSelected}" />
rmoore
fonte
2
Não vi a parte relacionada, mas você pode fazer a mesma coisa, definindo o fundo e a borda como quiser na propriedade IsMouseOver.
rmoore
88
Resolvi ainda melhor agora - <Setter Property = "Focusable" Value = "false" /> desativa completamente a seleção da linha.
Martin Konicek
8
Ahh, achei que você quisesse dizer apenas desligar a seleção visualmente. Se você não quiser que eles sejam selecionados, você pode querer dar uma olhada em como usar um ItemsControl (uma vez que você ainda pode definir os itens selecionados por meio de código se eles não forem focalizáveis), embora para obter a aparência de grade você terei que fazer algo como isto: manicprogrammer.com/cs/blogs/… Além disso, se ainda não o fez, você pode dar uma olhada no livro WPF Unleashed, pois ele fornece uma ótima introdução ao WPF e XAML.
rmoore
2
@MartinKonicek eu sei que é uma postagem antiga, mas seu comentário bem avaliado deve ser uma resposta;)
WiiMaxx
1
@MartinKonicek Eu tive que adicionar BasedOn="{StaticResource {x:Type ListViewItem}}"para que não substituísse o resto dos meus estilos de grade, mas também acho que você deve fazer seu comentário como a resposta aceita
JumpingJezza
31

A resposta de Moore não funciona, e a página aqui:

Especificando a Cor de Seleção, Alinhamento de Conteúdo e Cor de Fundo para itens em uma ListBox

explica por que não pode funcionar.

Se o seu listview contém apenas texto básico, a maneira mais simples de resolver o problema é usar pincéis transparentes.

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

Isso produzirá resultados indesejáveis ​​se as células do listview estiverem segurando controles como caixas de combinação, uma vez que também muda sua cor. Para resolver este problema, você deve redefinir o modelo do controle.

  <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
fonte
14
Isso faz com que todos os meus itens na minha ListView desapareçam
Chuck Savage
18

Defina o estilo de cada ListViewItem para ter Focusable definido como false.

<ListView ItemsSource="{Binding Test}" >
    <ListView.ItemContainerStyle>
        <Style TargetType="{x:Type ListViewItem}">
            <Setter Property="Focusable" Value="False"/>
        </Style>
    </ListView.ItemContainerStyle>
</ListView>
Hayley Guillou
fonte
4
Simples e eficiente. E realmente faz o que é solicitado: desativa a seleção em vez de apenas ocultá-la. Esta é a melhor resposta.
Fumidu
13

Este é o modelo padrão para ListViewItem do Blend:

Modelo ListViewItem padrão:

        <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 remover o IsSelected Trigger e o IsSelected / IsSelectionActive MultiTrigger, adicionando o código abaixo ao seu estilo para substituir o modelo padrão e não haverá nenhuma mudança visual quando selecionado.

Solução para desativar as alterações visuais da propriedade 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
fonte
12

A maneira mais fácil que encontrei:

<Setter Property="Focusable" Value="false"/>
Martin Konicek
fonte
4
@Mutex Funciona - você tem que aplicar isso ListView.ItemContainerStyle!
Andreas Niedermair
8

Na sequência da solução acima ... Eu usaria um MultiTrigger para permitir que os destaques do MouseOver continuem a funcionar após a seleção, de modo que o estilo do seu ListViewItem seja:

        <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>
Cachorro vermelho
fonte
6

Ok, um pouco tarde para o jogo, mas nenhuma dessas soluções fez exatamente o que eu estava tentando fazer. Essas soluções têm alguns problemas

  1. Desative o ListViewItem, que confunde os estilos e desativa todos os controles filhos
  2. Remova da pilha de hit-test, ou seja, os controles filhos nunca passam por cima ou clicam
  3. Tornar não focalizável, isso simplesmente não funcionou para mim?

Eu queria um ListView com os cabeçalhos de agrupamento, e cada ListViewItem deveria ser apenas 'informativo' sem seleção ou foco, mas o ListViewItem tem um botão que eu desejo que possa ser clicado e passar o mouse.

Então, realmente o que eu quero é que o ListViewItem não seja um ListViewItem, então, eu mudei o ControlTemplate do ListViewItem e apenas o tornei um ContentControl simples.

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

Uma das propriedades do listview é IsHitTestVisible. Desmarque-o.

Jacob Levertov
fonte
Simples e eficaz, também resolvo meu problema com ScrollViewer embrulhado em uma exibição de lista.
Brian Ng
1
Eu tenho o modelo de botão dentro do modelo de item do listview. se desmarcar, IsHitTestVisibleo botão não pode ser clicado. Ele age comoIsEnabled = false;
Luiey
1

Isso é para outras pessoas que podem encontrar os seguintes requisitos:

  1. Substituir totalmente a indicação visual de "selecionado" (por exemplo, usar algum tipo de forma), além de apenas alterar a cor do destaque padrão
  2. Inclui esta indicação selecionada no DataTemplate junto com as outras representações visuais do seu modelo, mas,
  3. Não queira ter que adicionar uma propriedade "IsSelectedItem" à sua classe de modelo e se preocupar com a manipulação manual dessa propriedade em todos os objetos de modelo.
  4. Exige que os itens sejam selecionáveis ​​no ListView
  5. Também gostaria de substituir a representação visual de IsMouseOver

Se você é como eu (usando WPF com .NET 4.5) e descobriu que as soluções que envolvem gatilhos de estilo simplesmente não funcionavam, aqui está minha solução:

Substitua o ControlTemplate do ListViewItem em um estilo:

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

Resulta nisso em tempo de execução (item 'B' é selecionado, item 'D' passa o mouse):

Aparência de ListView

BCA
fonte
1

Use o código abaixo:

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

O código abaixo desabilita a seleção de linha ListViewItem e também permite adicionar preenchimento, margem etc.

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

O código abaixo desativa o foco em 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
fonte