Welcome to OGeek Q&A Community for programmer and developer-Open, Learning and Share
Welcome To Ask or Share your Answers For Others

Categories

0 votes
502 views
in Technique[技术] by (71.8m points)

.net - ListBox mouse over background color

The problem I have is the MouseOver trigger to color the background fails on the selected row.
For any non-selected row the background turns blue on mouse over.
But no blue background for the selected row.
Click on a row and then the background blue goes away.

I also tried the style in the ListBox.ItemContainerStyle

<Window x:Class="ListBoxLastIntoView.MainWindow"
        xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
        xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
        Title="MainWindow" Height="350" Width="525">
    <Grid>
        <Grid.RowDefinitions>
            <RowDefinition Height="0"/>
            <RowDefinition Height="*"/>
        </Grid.RowDefinitions>
        <ListBox Grid.Row="1" Grid.ColumnSpan="2" x:Name="lvMVitems" 
            ItemsSource="{Binding Mode=OneWay}" 
            ScrollViewer.CanContentScroll="False" ScrollViewer.HorizontalScrollBarVisibility="Disabled" ScrollViewer.VerticalScrollBarVisibility="Auto" MaxHeight="300">
            <ListBox.Resources>
                <Style TargetType="ListBoxItem">
                    <Style.Resources>
                        <!-- Background of selected item when focussed -->
                        <SolidColorBrush x:Key="{x:Static SystemColors.HighlightBrushKey}" Color="Transparent"/>
                        <!-- Background of selected item when not focussed -->
                        <SolidColorBrush x:Key="{x:Static SystemColors.InactiveSelectionHighlightBrushKey}" Color="Transparent" />
                    </Style.Resources>
                    <Style.Triggers>
                        <Trigger Property="IsMouseOver" Value="True">
                            <Setter Property="Background" Value="LightSteelBlue" />
                        </Trigger>
                    </Style.Triggers>
                </Style>                 
            </ListBox.Resources>
            <!--<ListBox.ItemContainerStyle>               
            </ListBox.ItemContainerStyle>-->
            <ListBox.ItemTemplate>
                <DataTemplate>
                    <TextBlock Text="{TemplateBinding Content}" Background="Orange" Margin="20,2,2,2">
                    </TextBlock>
                </DataTemplate>
            </ListBox.ItemTemplate>
        </ListBox>
    </Grid>
</Window>


namespace ListBoxLastIntoView
{
    public partial class MainWindow : Window
    {
        private string lorum = "Lorem ipsum dolor sit amet, consectetur adipisicing elit, sed do eiusmod tempor incididunt ut labore et dolore magna aliqua. Ut enim ad minim veniam, quis nostrud exercitation ullamco laboris nisi ut aliquip ex ea commodo consequat. Duis aute irure dolor in reprehenderit in voluptate velit esse cillum dolore eu fugiat nulla pariatur. Excepteur sint occaecat cupidatat non proident, sunt in culpa qui officia deserunt mollit anim id est laborum.";
        private List<string> lorums = new List<string>();
        public MainWindow()
        {
            for (int i = 1; i < 100; i++) lorums.Add(i.ToString() + " " + lorum);           
            InitializeComponent();
            //lb.ItemsSource = lorums;
            lvMVitems.ItemsSource = lorums;
        }
    }
}
See Question&Answers more detail:os

与恶龙缠斗过久,自身亦成为恶龙;凝视深渊过久,深渊将回以凝视…
Welcome To Ask or Share your Answers For Others

1 Reply

0 votes
by (71.8m points)

If you look at the default template of ListBoxItem, you will see the IsMouseOver trigger is applied before the IsSelected trigger. Since DataTriggers are evaluated from top to bottom, the last trigger will always win and set the Background of ListBoxItem as Transparent (in your case).

If you want to override that behavior, you'll have to override default template and change ordering of triggers. Below is a sample showing how to do it, you can change background colors and border brushes as per your needs:

<Style TargetType="ListBoxItem">
  <Setter Property="Template">
     <Setter.Value>
       <ControlTemplate TargetType="ListBoxItem">
          <Border BorderThickness="{TemplateBinding Border.BorderThickness}"
                  Padding="{TemplateBinding Control.Padding}"
                  BorderBrush="{TemplateBinding Border.BorderBrush}"
                  Background="{TemplateBinding Panel.Background}"
                  Name="Bd"
                  SnapsToDevicePixels="True">
             <ContentPresenter Content="{TemplateBinding ContentControl.Content}"
                               ContentTemplate="{TemplateBinding ContentControl.ContentTemplate}"
                               ContentStringFormat="{TemplateBinding ContentControl.ContentStringFormat}"
                               HorizontalAlignment="{TemplateBinding Control.HorizontalContentAlignment}"
                               VerticalAlignment="{TemplateBinding Control.VerticalContentAlignment}"
                               SnapsToDevicePixels="{TemplateBinding UIElement.SnapsToDevicePixels}" />
          </Border>
          <ControlTemplate.Triggers>
             <MultiTrigger>
                <MultiTrigger.Conditions>
                  <Condition Property="Selector.IsSelectionActive" Value="False"/>
                  <Condition Property="Selector.IsSelected" Value="True"/>
                </MultiTrigger.Conditions>
                <Setter Property="Panel.Background" TargetName="Bd" 
                        Value="Transparent"/>
                <Setter Property="Border.BorderBrush" TargetName="Bd">
                   <Setter.Value>
                     <SolidColorBrush>#FFDADADA</SolidColorBrush>
                   </Setter.Value>
                </Setter>
             </MultiTrigger>
             <MultiTrigger>
               <MultiTrigger.Conditions>
                 <Condition Property="Selector.IsSelectionActive" Value="True"/>
                 <Condition Property="Selector.IsSelected" Value="True"/>
               </MultiTrigger.Conditions>
               <Setter Property="Panel.Background" TargetName="Bd" Value="Transparent"/>
               <Setter Property="Border.BorderBrush" TargetName="Bd">
                 <Setter.Value>
                   <SolidColorBrush>#FF26A0DA</SolidColorBrush>
                 </Setter.Value>
               </Setter>
             </MultiTrigger>
             <Trigger Property="UIElement.IsMouseOver" Value="True">
               <Setter Property="Panel.Background" TargetName="Bd" 
                       Value="LightSteelBlue"/>
               <Setter Property="Border.BorderBrush" TargetName="Bd">
                 <Setter.Value>
                   <SolidColorBrush>#A826A0DA</SolidColorBrush>
                 </Setter.Value>
               </Setter>
             </Trigger>
             <Trigger Property="UIElement.IsEnabled" Value="False">
               <Setter Property="TextElement.Foreground" TargetName="Bd">
                 <Setter.Value>
                   <DynamicResource ResourceKey="{x:Static SystemColors.GrayTextBrushKey}" />
                 </Setter.Value>
               </Setter>
             </Trigger>
          </ControlTemplate.Triggers>
       </ControlTemplate>
     </Setter.Value>
   </Setter>
</Style>

UPDATE

Maybe I should explain a bit more about my assertions above.

First of all, I had Windows 8 at my disposal and the default templates are quite different between Windows 7 and Windows 8. For Windows 8, theme styles are picked from PresentationFramework.Aero2.dll, hence the default templates might differ from theme style found under PresentationFramework.Aero.dll (used for Windows 7 and earlier versions).

I posted above the default template I got from Aero2.dll. As you can see, it doesn't use HighlightBrushKey so the suggestion of overriding HighlightBrushKey doesn't work in this case. (That's why I don't like overriding system brushes, since it might not work for templates using another theme style).

As per Dev's answer

Style triggers take precedence over template triggers anyways so it wouldn't matter if the template trigger is at first or last place in list.

I agree that Style triggers take precedence over template triggers. But, what I mentioned in my answer was the case when you haven't used any Style triggers and simply provide values in the template. In the default template the MouseOver trigger is at top and the SelectedItem trigger below that, so in that case order does matter. You can verify that yourself by moving up the trigger and removing all Style triggers.

And regarding

I am not sure if the style Rohit posted to you is a complete copy of the ListBoxItem style. There seem to be style setters missing. He just posted you the template I guess.

I have posted the complete template of ListBoxItem found under Aero2.dll which obviously might differ based on theme style.

I got the style using XamlWriter.Save(listBoxItem.Template, xmlwrite);


与恶龙缠斗过久,自身亦成为恶龙;凝视深渊过久,深渊将回以凝视…
OGeek|极客中国-欢迎来到极客的世界,一个免费开放的程序员编程交流平台!开放,进步,分享!让技术改变生活,让极客改变未来! Welcome to OGeek Q&A Community for programmer and developer-Open, Learning and Share
Click Here to Ask a Question

...