wpf ListBox 鼠标悬停在背景颜色上

声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow 原文地址: http://stackoverflow.com/questions/21972818/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me): StackOverFlow

提示:将鼠标放在中文语句上可以显示对应的英文。显示中英文
时间:2020-09-13 11:00:14  来源:igfitidea点击:

ListBox mouse over background color

.netwpflistbox

提问by paparazzo

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.

我遇到的问题是在所选行上为背景着色的 MouseOver 触发器失败。
对于任何未选择的行,背景在鼠标悬停时变为蓝色。
但所选行没有蓝色背景。
单击一行,然后背景蓝色消失。

I also tried the style in the ListBox.ItemContainerStyle

我也尝试了 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;
        }
    }
}

回答by Rohit Vats

If you look at default template of ListBoxItem, you will see IsMouseOvertrigger is applied before IsSelectedtriggerand since dataTriggers are evaluated from top to bottom. So, last trigger always won and set background of ListBoxItem as Transparent(in your case).

如果您查看 ListBoxItem 的默认模板,您会看到IsMouseOver触发器在IsSelected触发器之前应用,并且因为 dataTriggers 是从上到下评估的。因此,最后一个触发器总是获胜并将 ListBoxItem 的背景设置为Transparent(在您的情况下)。

In case you want to override that behaviour, you have to override default templateand set your values over there and change ordering of triggers. Below is the sample 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

更新

May be I should explain a bit more about my assertions above.

也许我应该多解释一下我上面的断言。

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

首先,我可以使用 Windows 8,Windows 7 和 Windows 8 的默认模板完全不同。对于 Windows 8,主题样式是从 中选择的PresentationFramework.Aero2.dll,因此默认模板可能与下面找到的主题样式不同PresentationFramework.Aero.dll(用于 Windows 7 和早期版本)。

I have posted default template I got from Aero2.dll. As you can see in default template, it doesn't use HighlightBrushKeyso the question you posted where you are overriding HighlightBrushKeydoesn't work at first place. (That's why I don't like overriding System brushes since it might not work for templates using another Theme style).

我已经发布了我从Aero2.dll. 正如您在默认模板中看到的那样,它没有使用,HighlightBrushKey因此您在覆盖的位置发布的问题首先HighlightBrushKey不起作用。(这就是为什么我不喜欢覆盖系统画笔,因为它可能不适用于使用其他主题样式的模板)。

As per Dev's answer

根据 Dev 的回答

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 template. In default template MouseOverTriggeris at top and SelectedItemtrigger below that. So, in that case order does matter. You can verify that your self by moving up the trigger and removing all Style triggers.

我同意样式触发器优先于模板触发器。但是,我在回答中提到的是当您没有使用任何 Style 触发器而只是在模板中提供值时的情况。默认模板MouseOverTrigger在顶部并SelectedItem在其下方触发。因此,在这种情况下,顺序确实很重要。您可以通过向上移动触发器并移除所有样式触发器来验证您的自我。

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.

我不确定 Rohit 发布给您的样式是否是 ListBoxItem 样式的完整副本。似乎缺少样式设置器。他刚刚给你贴了我猜的模板。

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

我已经发布了 ListBoxItem 的完整模板,在Aero2.dll该模板下显然可能因主题风格而异。

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

我得到了使用的风格 XamlWriter.Save(listBoxItem.Template, xmlwrite);

回答by dev hedgehog

You have an iteressting issue there. I had it too awhile ago when writing a theme.

你在那里有一个迭代问题。前段时间写主题的时候也遇到过。

The problem is not order of triggers or which trigger is at bottom and which not.

问题不在于触发器的顺序,也不在于哪个触发器在底部,哪个不在。

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.

无论如何,样式触发器优先于模板触发器,因此模板触发器是在列表中的第一个还是最后一个位置都没有关系。

The problem you have is very rare in wpf. In your case the implict style's trigger is simply ignored because background of border is not matched to background of the templated parent.

您遇到的问题在 wpf 中非常罕见。在您的情况下,隐式样式的触发器被简单地忽略,因为边框背景与模板化父级的背景不匹配。

In your case a trigger is being called internally by microsoft when is selected property is true. Inside the trigger sets the background color directly on border element with the name "Bd" instead of setting the background on templated parent.

In your case a trigger is being called internally by microsoft when is selected property is true. 在触发器内部,直接在名为“Bd”的边框元素上设置背景颜色,而不是在模板化父项上设置背景。

The result is there are two different backgrounds.

结果是有两种不同的背景。

To make all that easy. You want to make following code run:

让这一切变得容易。你想让下面的代码运行:

<Style TargetType="ListBoxItem">
   <Style.Triggers>
       <Trigger Property="IsMouseOver" Value="True">
           <Setter Property="Background" Value="LightSteelBlue" />
       </Trigger>
   </Style.Triggers>
</Style>

Internally this is what happens in microsoft's style.

在内部,这就是微软的风格。

 <MultiTrigger>
   <MultiTrigger.Conditions>
     <Condition Property="Selector.IsSelectionActive" Value="True"/>
     <Condition Property="Selector.IsSelected" Value="True"/>
   </MultiTrigger.Conditions>
   <Setter Property="Background" TargetName="Bd" Value="Blue"/>
 </MultiTrigger>

Border "Bd" background gets a new value but your style's mouse over trigger mains templated parent's background. Therefore you end up having two different backgrounds.

边框“Bd”背景获得新值,但您的样式鼠标悬停在触发电源模板父背景上。因此,您最终拥有两种不同的背景。

This is right approach microsoft should have taken!

这是微软应该采取的正确方法!

 <MultiTrigger>
   <MultiTrigger.Conditions>
     <Condition Property="Selector.IsSelectionActive" Value="True"/>
     <Condition Property="Selector.IsSelected" Value="True"/>
   </MultiTrigger.Conditions>
   <Setter Property="Background" Value="Blue"/>
 </MultiTrigger>

Its the line <Setter Property="Background" Value="Blue"/>that makes the big change.

它的生产线<Setter Property="Background" Value="Blue"/>带来了巨大的变化。

With the approach I showed you you wouldn't end up having two different backgrounds.

使用我向您展示的方法,您最终不会拥有两种不同的背景。

Now that you know what is going wrong internally lets go to the most important part how to solve this issue.

现在您知道内部出了什么问题,让我们进入最重要的部分,如何解决这个问题。

The solution is... and at this point me and Rohit agree on same issue solving approach... unfortunately you will have to rewrite the style or copy past it and match backgrounds so there won't be standalone values for border element. Border element should listen to templated parent's background.

解决方案是……在这一点上,我和 Rohit 就相同的问题解决方法达成一致……不幸的是,您将不得不重写样式或复制它并匹配背景,因此边框元素不会有独立的值。边框元素应该听模板化父母的背景。

The best way to see the current default template is to use Blend and to pick the option to create copy of contro's template for edit.

查看当前默认模板的最佳方法是使用 Blend 并选择创建控件模板副本以进行编辑的选项。

There are also default templates of wpf controls somewhere on the internt. You could find the ListBoxItem style and copy past it before adding your edits to it.

互联网上的某处也有 wpf 控件的默认模板。您可以找到 ListBoxItem 样式并复制过去,然后再向其添加编辑。

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.

我不确定 Rohit 发布给您的样式是否是 ListBoxItem 样式的完整副本。似乎缺少样式设置器。他刚刚给你贴了我猜的模板。