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>
Ладно, немного поздно в игре, но ни одно из этих решений не совсем то, что я пытался сделать. У этих решений есть пара проблем
- Отключить ListViewItem, который запутывает стили и отключает все дочерние элементы управления
- Удалить из стека тестов на попадание, то есть дочерние элементы управления никогда не наведут курсор мыши или щелчок мышью
- Сделать это не на фокусе, это просто не работает для меня?
Я хотел 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
, рассмотрите возможность использования этого вместо этого.
Это для тех, кто может столкнуться со следующими требованиями:
- Полностью замените визуальную индикацию "выбрано" (например, используйте какую-то форму), за исключением простого изменения цвета стандартной подсветки
- Включите эту выбранную индикацию в шаблон данных вместе с другими визуальными представлениями вашей модели, но,
- Не нужно добавлять свойство IsSelectedItem к классу модели и обременять его ручным управлением всеми объектами модели.
- Требовать, чтобы элементы выбирались в ListView
- Также хотел бы заменить визуальное представление 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.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>