WPF ListView отключить выбор

У меня есть простой WPF ListView и простой вопрос:

Можно ли отключить выделение, чтобы, когда пользователь щелкает строку, строка не выделялась?

Посмотреть список

Я хотел бы, чтобы строка 1 выглядела как строка 0 при нажатии.

Возможно связано: могу ли я стилизовать вид наведения / выделения? Например. заменить синий вид градиента при наведении курсора (строка 3) на собственный сплошной цвет. Я нашел это и это, к сожалению, не помогает.

(Достижение того же самого без использования ListView также приемлемо. Я просто хотел бы использовать логическую прокрутку и виртуализацию пользовательского интерфейса, как это делает ListView)

XAML для 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>

15 ответов

Решение

Самый простой способ, который я нашел:

<Setter Property="Focusable" Value="false"/>

Согласно комментарию Мартина Коничека, чтобы полностью отключить выбор элементов самым простым способом:

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

Однако если вам все еще требуется функциональность ListView, например, возможность выбрать элемент, вы можете визуально отключить стилизацию выбранного элемента, например, так:

Вы можете сделать это несколькими способами, от изменения ControlTemplate объекта ListViewItem до просто установки стиля (намного проще). Вы можете создать стиль для ListViewItems, используя ItemContainerStyle и "отключить" фон и кисть границы, когда он выбран.

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

Кроме того, если у вас нет другого способа уведомления пользователя, когда элемент выбран (или только для тестирования), вы можете добавить столбец для представления значения:

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

Ответ Мура не работает, и страница здесь:

Указание цвета выделения, выравнивания содержимого и цвета фона для элементов в ListBox

объясняет, почему это не может работать.

Если ваш список содержит только основной текст, самый простой способ решить эту проблему - использовать прозрачные кисти.

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

Это приведет к нежелательным результатам, если ячейки списка содержат элементы управления, такие как комбинированные списки, так как это также меняет их цвет. Чтобы решить эту проблему, вы должны переопределить шаблон элемента управления.

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

Установите стиль каждого ListViewItem, чтобы Focusable был установлен в false.

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

Вот шаблон по умолчанию для ListViewItem из Blend:

Шаблон 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>

Просто удалите IsSelected Trigger и IsSelected/IsSelectionActive MultiTrigger, добавив приведенный ниже код в ваш стиль, чтобы заменить шаблон по умолчанию, и при выборе визуального изменения не будет.

Решение отключить визуальные изменения свойства 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>

Ладно, немного поздно в игре, но ни одно из этих решений не совсем то, что я пытался сделать. У этих решений есть пара проблем

  1. Отключить ListViewItem, который запутывает стили и отключает все дочерние элементы управления
  2. Удалить из стека тестов на попадание, то есть дочерние элементы управления никогда не наведут курсор мыши или щелчок мышью
  3. Сделать это не на фокусе, это просто не работает для меня?

Я хотел ListView с заголовками группировки, и каждый ListViewItem должен быть просто "информационным" без выделения или наведения на него, но в ListViewItem есть кнопка, которую я хочу сделать доступной для щелчка и наведения мыши.

Итак, на самом деле я хочу, чтобы ListViewItem вообще не был ListViewItem. Итак, я перебрал ControlTemplate объекта ListViewItem и просто сделал его простым 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>

В дополнение к решению, приведенному выше... Я бы использовал MultiTrigger, чтобы подсветка MouseOver продолжала работать после выбора таким образом, чтобы стиль вашего ListViewItem был:

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

Одним из свойств списка является IsHitTestVisible, Снимите это.

Используйте код ниже:

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

Другой аналогичный элемент управленияListViewиListBoxэто не предлагает выборItemsControl, рассмотрите возможность использования этого вместо этого.

Это для тех, кто может столкнуться со следующими требованиями:

  1. Полностью замените визуальную индикацию "выбрано" (например, используйте какую-то форму), за исключением простого изменения цвета стандартной подсветки
  2. Включите эту выбранную индикацию в шаблон данных вместе с другими визуальными представлениями вашей модели, но,
  3. Не нужно добавлять свойство IsSelectedItem к классу модели и обременять его ручным управлением всеми объектами модели.
  4. Требовать, чтобы элементы выбирались в ListView
  5. Также хотел бы заменить визуальное представление IsMouseOver

Если вы похожи на меня (используете WPF с.NET 4.5) и обнаружили, что решения, включающие триггеры стилей, просто не работают, вот мое решение:

Замените ControlTemplate объекта ListViewItem в стиле:

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

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

Результатом этого во время выполнения (выбран элемент "B", на элементе "D" наведен курсор мыши):

Внешний вид ListView

Еще один способ отключить выделение.

          <ListView ...>
        <ListView.ItemsPanel>
            <ItemsPanelTemplate>
                <VirtualizingStackPanel IsEnabled="False"/>
            </ItemsPanelTemplate>
        </ListView.ItemsPanel>
    </ListView>

Это как

      <ListView IsEnabled="False"> 

но без отключенного скроллера

              <ListView Grid.Row="1" ItemsSource="{Binding Properties}" >
            <!--Disable selection of items-->
            <ListView.Resources>
                <Style TargetType="{x:Type ListViewItem}">
                    <Setter Property="Background" Value="Transparent" />
                    <Setter Property="BorderBrush" Value="Transparent"/>
                    <Setter Property="VerticalContentAlignment" Value="Center"/>
                    <Setter Property="Template">
                        <Setter.Value>
                            <ControlTemplate TargetType="{x:Type ListViewItem}">
                                <Grid Background="{TemplateBinding Background}">
                                    <Border Name="Selection" Visibility="Collapsed" />
                                    <!-- This is used when GridView is put inside the ListView -->
                                    <GridViewRowPresenter Grid.RowSpan="2"
                                      Margin="{TemplateBinding Padding}"
                                      HorizontalAlignment="{TemplateBinding HorizontalContentAlignment}"
                                      VerticalAlignment="{TemplateBinding VerticalContentAlignment}"
                                      SnapsToDevicePixels="{TemplateBinding SnapsToDevicePixels}"/>

                                </Grid>
                            </ControlTemplate>
                        </Setter.Value>
                    </Setter>
                </Style>
            </ListView.Resources>
            <ListView.View>
                <GridView>
                    <GridViewColumn Width="90" DisplayMemberBinding="{Binding Name}"  />
                    <GridViewColumn Width="90" CellTemplateSelector="{StaticResource customCellTemplateSelector}"  />
                </GridView>
            </ListView.View>
        </ListView>

Код ниже отключает выбор строки ListViewItem, а также позволяет добавлять отступы, поля и т. Д.

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

Ниже кода отключить фокус на 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>

Другие вопросы по тегам