Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

How to remove gradient effect appearing for IsMouseOver in WPF ListViewItem's style?

Tags:

c#

wpf

xaml

In the following Window I define a trigger for IsMouseOver. The background color is changed correctly, but it has an gradient effect. See the pic below. How to get rid of the effect? enter image description here

Only Theme.DataGrid.Row.Background.Hover is moved from separate style file to code excerpt below.

<Window x:Class="MyCompany.Application.Shared.UI.Dialogs.SomeWindow
        xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
        xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
        xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
        xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
        mc:Ignorable="d"
        Title="MainWindow" Height="350" Width="525" Background="#FFF3F3F7">
    <Window.Resources>
        <SolidColorBrush x:Key="Theme.DataGrid.Row.BorderBrush" Color="#FFF3F3F7" options:Freeze="True" />
        <SolidColorBrush x:Key="Theme.DataGrid.Row.Background" Color="White" options:Freeze="True" />
        <SolidColorBrush x:Key="Theme.DataGrid.Row.Background.Hover" Color="#FFAEAEB6" options:Freeze="True" />
        <SolidColorBrush x:Key="Theme.DataGrid.Row.Background.Active" Color="#FF0D6AA8" options:Freeze="True" />
        <SolidColorBrush x:Key="Theme.DataGrid.Row.Background.HoverSelected" Color="#FF009AD9" options:Freeze="True" />
        <SolidColorBrush x:Key="Theme.DataGrid.Row.Background.Disabled" Color="#FFAEAEB6" options:Freeze="True" />
        <SolidColorBrush x:Key="Theme.DataGrid.Row.Foreground.Selected" Color="White" options:Freeze="True" />

        <Style x:Key="GridView.ColumnHeader.Gripper.Style" TargetType="{x:Type Thumb}">
            <Setter Property="Width" Value="8" />
            <Setter Property="Background" Value="Transparent" />
            <Setter Property="Cursor" Value="SizeWE" />
            <Setter Property="Template">
                <Setter.Value>
                    <ControlTemplate TargetType="{x:Type Thumb}">
                        <Border Background="{TemplateBinding Background}" Padding="{TemplateBinding Padding}" />
                    </ControlTemplate>
                </Setter.Value>
            </Setter>
        </Style>

        <Style TargetType="{x:Type GridViewColumnHeader}" >
            <EventSetter Event="FrameworkElement.Loaded" Handler="GridViewColumnHeader_Loaded"/>
            <Setter Property="FontWeight" Value="Bold"/>
            <Setter Property="BorderBrush" Value="Transparent"/>
            <Setter Property="BorderThickness" Value="0"/>
            <Setter Property="Background" Value="{StaticResource Theme.DataGrid.ColumnHeader.Background}"/>
            <Setter Property="Foreground" Value="Black"/>
            <Setter Property="HorizontalContentAlignment" Value="Left"/>
            <Setter Property="Template">
                <Setter.Value>
                    <ControlTemplate TargetType="{x:Type GridViewColumnHeader}">
                        <Grid>
                            <Grid.ColumnDefinitions>
                                <ColumnDefinition Width="*" />
                                <ColumnDefinition Width="1" />
                            </Grid.ColumnDefinitions>
                            <Border Grid.Column="0"  x:Name="Border" BorderBrush="{TemplateBinding BorderBrush}"
                        BorderThickness="{TemplateBinding BorderThickness}"
                            Background="{TemplateBinding Background}">
                                <ContentPresenter Margin="{TemplateBinding Padding}" HorizontalAlignment="{TemplateBinding HorizontalContentAlignment}" 
                                      VerticalAlignment="{TemplateBinding VerticalContentAlignment}" />
                            </Border>
                            <Thumb Grid.Column="1" x:Name="PART_HeaderGripper" HorizontalAlignment="Right" Style="{DynamicResource Theme.DataGrid.ColumnHeader.Gripper.Style}"/>
                        </Grid>
                    </ControlTemplate>
                </Setter.Value>
            </Setter>
        </Style>

        <Style TargetType="{x:Type ListView}" >
            <Setter Property="BorderThickness" Value="{DynamicResource Theme.DataGrid.BorderThickness}"/>
            <Setter Property="Background" Value="{StaticResource Theme.TreeView.Background}"/>
        </Style>

        <Style TargetType="{x:Type ListViewItem}" >
            <Setter Property="Background" Value="White" />
            <Setter Property="Foreground" Value="{DynamicResource Theme.DataGrid.Row.Foreground}" />
            <Setter Property="VerticalAlignment" Value="Stretch"/>
            <Setter Property="HorizontalAlignment" Value="Stretch"/>
            <Setter Property="VerticalContentAlignment" Value="Stretch"/>
            <Setter Property="HorizontalContentAlignment" Value="Stretch"/>
            <Setter Property="BorderThickness" Value="0"/>
            <Setter Property="BorderBrush" Value="Transparent"/>
            <Setter Property="Padding" Value="{DynamicResource Theme.DataGrid.Cell.Padding}"/>
            <Setter Property="Margin" Value="1"/>
            <Style.Triggers>
                <Trigger Property="IsMouseOver" Value="True">
                    <Setter Property="Background" Value="{DynamicResource Theme.DataGrid.Row.Background.Hover}" />
                </Trigger>
                <Trigger Property="IsSelected" Value="True">
                    <Setter Property="Background" Value="{DynamicResource Theme.DataGrid.Row.Background.Active}" 
                    <Setter Property="Foreground" Value="{DynamicResource Theme.DataGrid.Row.Background.Selected}" />
                </Trigger>
                <Trigger Property="IsEnabled" Value="False">
                    <Setter Property="Background" Value="{DynamicResource Theme.DataGrid.Row.Background.Disabled}" />
                </Trigger>
                <MultiTrigger>
                    <MultiTrigger.Conditions>
                        <Condition Property="IsMouseOver" Value="True" />
                        <Condition Property="IsSelected" Value="True" />
                    </MultiTrigger.Conditions>
                    <Setter Property="Background" Value="{DynamicResource Theme.DataGrid.Row.Background.HoverSelected}" />
                </MultiTrigger>
            </Style.Triggers>
        </Style>
    </Window.Resources>

    <StackPanel>
        <CheckBox Content="IsGrouped"  IsChecked="{Binding IsGrouped}"/>
        <ListView Margin="10" ItemsSource="{Binding Users}">    
            <ListView.View>
                <GridView AllowsColumnReorder="False">
                    <GridViewColumn Header="Name" DisplayMemberBinding="{Binding Name}" />
                    <GridViewColumn Header="Age"  DisplayMemberBinding="{Binding Age}" />
                    <GridViewColumn Header="Mail"  DisplayMemberBinding="{Binding Mail}" />
                    <GridViewColumn Header="Group"  DisplayMemberBinding="{Binding Group}" />
        </ListView>
    </StackPanel>
</Window>

ViewModel (note that this uses our own ViewModel-class that i.e raises PropertyChanged events)

namespace MyCompany.Application.Shared.UI.Dialogs
{
    public class User
    {
        public string Name { get; set; }

        public int Age { get; set; }

        public string Mail { get; set; }

        public string Group { get; set; }
    }

    public class SomeWindowViewModel : ViewModel
    {
        List<User> items = new List<User>();

        IEnumerable<User> GetUsers()
        {
            foreach (var item in items)
            {
                yield return item;
            }
        }
        public ICollectionView Users { get; }

        private bool _isGrouped = false;
        public bool IsGrouped
        {
            get { return _isGrouped; }
            set
            {
                _isGrouped = value;
                if (value)
                {
                    Users.GroupDescriptions.Add(new PropertyGroupDescription("Group"));
                }
                else
                {
                    Users.GroupDescriptions.Clear();
                }
            }
        }

        public SomeWindowViewModel()
        {
            items.Add(new User() { Name = "John Doe", Age = 42, Mail = "[email protected]", Group = "OneGroup1" });
            items.Add(new User() { Name = "Jane Doe", Age = 39, Mail = "[email protected]", Group = "OneGroup1" });
            items.Add(new User() { Name = "Sammy Doe", Age = 7, Mail = "[email protected]", Group = "TwoGroup2" });
            items.Add(new User() { Name = "Pentti Doe", Age = 7, Mail = "[email protected]", Group = "TwoGroup2" });
            Users = CollectionViewSource.GetDefaultView(GetUsers());
        }
    }
}
like image 669
char m Avatar asked Mar 09 '18 20:03

char m


1 Answers

I had some issues with the given code sample, e.g. missing resources or additional options:Freeze="true" which could not be resolved, therefore my solution may look a little different, but I think it does what you want: it removes the gradient effect.


The issue is that the default ListViewItem template has triggers which change the background (as you have found out as well) and the way around is to use a simplified ControlTemplate without any triggers.

This example of a simplified template works and you can put it in your {x:Type ListViewItem} to get a look like shown in the pictures below.

<Setter Property="Template">
    <Setter.Value>
        <ControlTemplate TargetType="{x:Type ListViewItem}">
            <Border Padding="{TemplateBinding Padding}"
                    Background="{TemplateBinding Background}"
                    BorderBrush="{TemplateBinding BorderBrush}"
                    BorderThickness="{TemplateBinding BorderThickness}"
                    SnapsToDevicePixels="true">
                <GridViewRowPresenter HorizontalAlignment="{TemplateBinding HorizontalContentAlignment}"
                                      VerticalAlignment="{TemplateBinding VerticalContentAlignment}"
                                      SnapsToDevicePixels="{TemplateBinding SnapsToDevicePixels}" />
            </Border>
        </ControlTemplate>
    </Setter.Value>
</Setter>

Using that template, this is what it will look like if you first selected "Sammy Doe 7" and then hover over "Jane Doe 39",

enter image description here

and this is how it looks when you select (e.g. click on) "Jane Doe 39":

enter image description here


I'm not entirely sure what you mean with

as jsanalytics points out control template results in rows to be class names and not the data

but as far as I understand it, above code should not lead to that behavior. If it does, let me know and I will find another solution.

like image 183
Thomas Flinkow Avatar answered Oct 08 '22 17:10

Thomas Flinkow