How to set a WPF ListView Selected Item color?
Asked Answered
B

2

16

I am trying to recreate the Mail UI from Windows 8 in a WPF application running on Windows 7. Here's what I want to achieve:

Target UI

In particular, I don't know how to change the background color for selected items e.g. the Inbox item in the first column and the mail from Twitter in the second column. I have tried several solutions from other similar Stackoverflow Questions but none seem to work for me. e.g.

Selected item loses style when focus moved out in WPF ListBox

WPF ListView Inactive Selection Color

Here is the code I have for my listview:

<ListView Grid.Row="0" SelectedItem="{Binding Path=SelectedArea}" ItemsSource="{Binding Path=Areas}" Background="#DCE3E5" >

                    <ListView.Resources>

                        <!-- Template that is used upon selection of an Area -->
                        <ControlTemplate x:Key="SelectedTemplate" TargetType="ListViewItem">
                            <Border Background="#388095" Cursor="Hand" >
                                <TextBlock Text="{Binding Name}" Margin="5" />
                            </Border>                                
                        </ControlTemplate>

                        <Style TargetType="ListViewItem">
                            <Setter Property="Template">
                                <Setter.Value>                                        
                                    <!-- Base Template that is replaced upon selection -->
                                    <ControlTemplate TargetType="ListViewItem">
                                        <Border Background="#DCE3E5" Cursor="Hand"  >
                                            <TextBlock Text="{Binding Name}" Margin="5" />
                                        </Border>
                                    </ControlTemplate>
                                </Setter.Value>
                            </Setter>
                            <Style.Triggers>
                                <MultiTrigger>
                                    <MultiTrigger.Conditions>
                                        <Condition Property="IsSelected" Value="true" />
                                    </MultiTrigger.Conditions>
                                    <Setter Property="Template" Value="{StaticResource SelectedTemplate}" />
                                </MultiTrigger>
                            </Style.Triggers>
                        </Style>

                    </ListView.Resources>                        

                </ListView>

How can I change the background color of the selected item? And how do I retain the color change when the focus changes.

Bakeman answered 12/2, 2013 at 17:44 Comment(0)
A
21

I did something similar to this recently:

<ListView.Resources>                
    <ControlTemplate x:Key="SelectedTemplate" TargetType="ListViewItem">
        <Border CornerRadius="5" BorderThickness="1" BorderBrush="DarkGray" Background="#FF92C6F9" Padding="2" HorizontalAlignment="Left" Margin="5" Tag="{Binding Value}" Cursor="Hand" MouseUp="Border_MouseUp_1">                        
            <TextBlock Text="{Binding Name}" Margin="5" />
        </Border>
    </ControlTemplate>
    <Style TargetType="ListViewItem">
        <Setter Property="Template">
            <Setter.Value>
                <ControlTemplate TargetType="ListViewItem">
                    <Border CornerRadius="5" BorderThickness="1" BorderBrush="DarkGray" Background="WhiteSmoke" Padding="2" HorizontalAlignment="Left" Margin="5" Tag="{Binding Value}" Cursor="Hand" MouseUp="Border_MouseUp_1" >                                    
                        <TextBlock Text="{Binding Name}" Margin="5" />
                    </Border>
                </ControlTemplate>
            </Setter.Value>
        </Setter>
        <Style.Triggers>
            <MultiTrigger>
                <MultiTrigger.Conditions>
                    <Condition Property="IsSelected" Value="true" />
                    <Condition Property="Selector.IsSelectionActive" Value="true" />
                </MultiTrigger.Conditions>                            
                <Setter Property="Template" Value="{StaticResource SelectedTemplate}" />                            
            </MultiTrigger>
        </Style.Triggers>
    </Style>
</ListView.Resources>

I believe removing:

<Condition Property="Selector.IsSelectionActive" Value="true" />

will allow you to keep the background color after focus is lost.

EDIT:

In response to your question below:

You can bind the tag property of the TextBlock to the command parameter, and then execute the command on the MouseUp event of the TextBlock:

<TextBlock x:Name="MyTextBlock" Text="Click Me!" Tag="{Binding MyCommandParameter}" MouseUp="MyTextBlock_MouseUp" />

And in the code behind:

    private void MyTextBlock_MouseUp(object sender, MouseButtonEventArgs e)
    {
        TextBlock tb = sender as TextBlock;

        if (tb != null && tb.Tag != null)
        {
            ViewModel.MyCommand.Execute(tb.Tag);
        }            
    }
Aziza answered 12/2, 2013 at 18:59 Comment(3)
Thanks @TrueEddie. My machine is acting up and I am not able to test your solution. I will get back as soon as I am able to fix my machine.Bakeman
This shows the selection properly. But now that we are using TextBlock instead of the hyperlink I was using, I am no longer able to supply the Command that I needed to invoke. How can I supply the command and associated parameter? When I replace your Border element with hyperlink, it allows me to change color when clicked outside the hyperlink but doesn't let me invoke the command. When I click the hyperlink, it allows me to inovke the command but the color isn't changed.Bakeman
The edits didn't work for me but I was able to bind the ListView SelectedItem to a Dependency Property I created in my MVVM model and load the next listview on the change of this property. This removed the need for the hyperlink and I already got the background color from your code. So, now I have the complete solution. Thanks so much for your help. I am posting the final ListView in my question in a few minutes.Bakeman
T
10

Just adding to "TrueEddie" point.

The other option would be "ItemContainerStyle" in ListView.

  <ListView Grid.Row="1" Grid.Column="0" Grid.ColumnSpan="2" 


                  BorderThickness="0" 
                     ItemContainerStyle="{StaticResource ListViewSmartNotes}"
                  SelectedItem="{Binding SelectedSmartNotes, Mode=TwoWay}"
                  ItemsSource="{Binding LstSmartNotes, Mode=TwoWay}" 
                  ItemTemplate="{DynamicResource ListViewItemOptionStyle}">


        </ListView>

ListViewItemOptionStyle defined in Style.xml

<Style x:Key="ListViewItemOptionStyle" TargetType="ListViewItem">
        <Setter Property="Template">
            <Setter.Value>
                <!-- Trun off default selection-->
                <ControlTemplate TargetType="{x:Type ListViewItem}">
                    <Border x:Name="Bd" BorderBrush="Gray" BorderThickness="0,1,0,1" 
                            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>
    <Style.Triggers>
        <MultiTrigger>
            <MultiTrigger.Conditions>
                <Condition Property="IsSelected" Value="True" />
            </MultiTrigger.Conditions>
            <MultiTrigger.Setters>
                <Setter Property="Background" Value="Green" />
                <Setter Property="BorderBrush" Value="Green" />
                <Setter Property="Foreground" Value="White"/>
            </MultiTrigger.Setters>
        </MultiTrigger>
    </Style.Triggers>
</Style>

Fore more details

https://sites.google.com/site/greateindiaclub/mobil-apps/windows8/wpfimportantbindings

Tinhorn answered 11/11, 2014 at 4:26 Comment(1)
I believe your ItemContainerStyle and ItemTemplate bindings are reversed and should read ItemContainerStyle="{StaticResource ListViewItemOptionStyle}", else you will get a conversion exception. Also, it may be just me, I would recommend using <GridViewRowPresenter Content="{TemplateBinding Content}" /> over using <ContentPresenter />, if there are multiple columns involved.Irick

© 2022 - 2024 — McMap. All rights reserved.