WPF ListView turn off selection
WpfListviewWpf Problem Overview
Is it possible to turn off the selection of a WPF ListView
, so when user clicks row, the row is not highlighted?
I would like the row 1 to look just like row 0 when clicked.
Possibly related: can I style the look of the hover / selection? Eg. to replace the blue gradient hover look (line 3) with a custom solid color. I have found this and this, unfortunately not helping.
(Achieving the same without using ListView is acceptable too. I'd just like to be able to use logical scrolling and UI virtualization as ListView does)
The XAML for ListView is:
<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>
Wpf Solutions
Solution 1 - Wpf
Per Martin Konicek's comment, to fully disable the selection of the items in the simplest manner:
<ListView>
<ListView.ItemContainerStyle>
<Style TargetType="ListViewItem">
<Setter Property="Focusable" Value="false"/>
</Style>
</ListView.ItemContainerStyle>
...
</ListView>
However if you still require the functionality of the ListView, like being able to select an item, then you can visually disable the styling of the selected item like so:
You can do this a number of ways, from changing the ListViewItem's ControlTemplate to just setting a style (much easier). You can create a style for the ListViewItems using the ItemContainerStyle and 'turn off' the background and border brush when it is selected.
<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>
Also, unless you have some other way of notifying the user when the item is selected (or just for testing) you can add a column to represent the value:
<GridViewColumn Header="IsSelected"
DisplayMemberBinding="{Binding RelativeSource={RelativeSource Mode=FindAncestor, AncestorType={x:Type ListViewItem}}, Path=IsSelected}" />
Solution 2 - Wpf
Moore's answer doesn't work, and the page here:
Specifying the Selection Color, Content Alignment, and Background Color for items in a ListBox
explains why it cannot work.
If your listview only contains basic text, the simplest way to solve the problem is by using transparent brushes.
<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>
This will produce undesirable results if the listview's cells are holding controls such as comboboxes, since it also changes their color. To solve this problem, you must redefine the control's template.
<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>
Solution 3 - Wpf
Set the style of each ListViewItem to have Focusable set to false.
<ListView ItemsSource="{Binding Test}" >
<ListView.ItemContainerStyle>
<Style TargetType="{x:Type ListViewItem}">
<Setter Property="Focusable" Value="False"/>
</Style>
</ListView.ItemContainerStyle>
</ListView>
Solution 4 - Wpf
Here's the default template for ListViewItem from Blend:
Default ListViewItem Template:
<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>
Just remove the IsSelected Trigger and IsSelected/IsSelectionActive MultiTrigger, by adding the below code to your Style to replace the default template, and there will be no visual change when selected.
Solution to turn off the IsSelected property's visual changes:
<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>
Solution 5 - Wpf
The easiest way I found:
<Setter Property="Focusable" Value="false"/>
Solution 6 - Wpf
Further to the solution above... I would use a MultiTrigger to allow the MouseOver highlights to continue to work after selection such that your ListViewItem's style will be:
<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>
Solution 7 - Wpf
Okay, little late to the game, but none of these solutions quite did what I was trying to do. These solutions have a couple problems
- Disable the ListViewItem, which screws up the styles and disables all the children controls
- Remove from the hit-test stack, i.e. children controls never get a mouse-over or click
- Make it not focusable, this just plain didn't work for me?
I wanted a ListView with the grouping headers, and each ListViewItem should just be 'informational' without selection or hover over, but the ListViewItem has a button in it that I want to be click-able and have hover-over.
So, really what I want is the ListViewItem to not be a ListViewItem at all, So, I over rode the ListViewItem's ControlTemplate and just made it a simple 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>
Solution 8 - Wpf
One of the properties of the listview is IsHitTestVisible
.
Uncheck it.
Solution 9 - Wpf
Use the code below:
<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>
</ListView.ItemContainerStyle>
Solution 10 - Wpf
This is for others who may encounter the following requirements:
- Completely replace the visual indication of "selected" (e.g. use some kind of shape), beyond just changing the color of the standard highlight
- Include this selected indication in the DataTemplate along with the other visual representations of your model, but,
- Don't want to have to add an "IsSelectedItem" property to your model class and be burdened with manually manipulating that property on all model objects.
- Require items to be selectable in the ListView
- Also would like to replace the visual representation of IsMouseOver
If you're like me (using WPF with .NET 4.5) and found that the solutions involving style triggers simply didn't work, here's my solution:
Replace the ControlTemplate of the ListViewItem in a style:
<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>
..And the 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>
Results in this at runtime (item 'B' is selected, item 'D' has mouse over):
Solution 11 - Wpf
Below code disables ListViewItem row selection and also allows to add padding, margin 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>
Solution 12 - Wpf
Below code disable Focus on 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>
Solution 13 - Wpf
<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>