.NET 4.5下的列表/组合框背景和选定颜色

14

我的应用程序一直在Windows 7及以下系统上运行,目标为.net 4框架。
如果现在将应用程序安装在Windows 8上(运行.net 4.5,但仍然以.net 4为目标),列表框或组合框中所选择的项会显示为蓝色背景,而聚焦项则显示为白色背景。有没有办法去掉这个效果?
我在XAML中使用以下代码来设置相关样式,这在Windows 8之前好像可以解决该问题。

<ListBox.ItemContainerStyle>
                <Style TargetType="{x:Type ListBoxItem}">
                    <Setter Property="FocusVisualStyle" Value="{x:Null}"/>
                    <Style.Resources>
                        <SolidColorBrush x:Key="{x:Static SystemColors.HighlightBrushKey}" Color="Transparent"/>
                        <SolidColorBrush x:Key="{x:Static SystemColors.ControlBrushKey}" Color="Transparent"/>
                    </Style.Resources>
                </Style>
            </ListBox.ItemContainerStyle>

1
你有没有找到这个问题的答案? - Anders Rune Jensen
1
我没有在Windows 8上测试过这个,所以aero2可能是问题所在,但在Windows 7上,我不得不使用.NET 4.5中的InactiveSelectionHighlightBrushKey而不是ControlBrushKey。 - Mike Fuchs
我想说的是,在 Aero2 模板中,许多颜色都是硬编码的。很遗憾。这包括 ComboBoxItem 和 MenuItem 等内容。如果你使用 Blend 或 VS 来编辑模板,这一点将显而易见。 - tofutim
6个回答

10

我忘记回来告诉大家我是怎么解决这个问题的了...原来你只需要创建一个空的项目容器样式并将其分配给列表框/组合框等就可以了。你可以同时使用这个空样式和你可能正在使用的当前样式,例如ListBox Style="{StaticResource CurrentStyle}" ItemContainerStyle="{StaticResource BlankListBoxContainerStyle}" /> 其中BlankListBoxContainerStyle将是类似于......

<Style x:Key="BlankListBoxContainerStyle" TargetType="{x:Type ListBoxItem}">
    <Setter Property="Template">
        <Setter.Value>
            <ControlTemplate TargetType="{x:Type ListBoxItem}">
                <ContentPresenter HorizontalAlignment="{TemplateBinding HorizontalContentAlignment}" SnapsToDevicePixels="{TemplateBinding SnapsToDevicePixels}" VerticalAlignment="{TemplateBinding VerticalContentAlignment}"/>
            </ControlTemplate>
        </Setter.Value>
    </Setter>
    <Setter Property="FocusVisualStyle"
            Value="{x:Null}"/>
</Style>

请查看我的答案,其中提供了一种不需要更改 ListBox 控件模板的解决方案。 - bugged87

6
你的应用程序重写了SystemColors.HighlightBrushKey(和其他系统键)的值。对于通过引用系统颜色定义其前景/背景颜色的控件而言,这样做是可行的,就像Win7默认主题(Aero)中所做的那样。
但是Win8默认主题(Aero2)以不同的方式定义颜色。因此,你的覆盖无效。

主题不必使用系统颜色。他们在Win7 / Aero中偶然使用了它们,但只是因为系统颜色被认为足够好用。

希望这可以帮到你。


2
谢谢,那很有道理。你知道我该如何阻止Aero2给我的应用程序着色吗? - Oli
奇怪的是,Aero2控件没有引用SystemColors,而是在代码中硬编码了颜色。一种解决方法,尽管很烦人,是覆盖模板。 - tofutim

4
重新阅读框架兼容性文档后,我发现在编译为.NET 4并在Windows 8上运行时实际上不需要它。

http://msdn.microsoft.com/en-us/library/system.windows.frameworkcompatibilitypreferences%28v=vs.110%29.aspx

但我仍然有一个蓝色的背景,这在Windows 7中并不存在,最终我发现问题出在一个列表视图上,它的样式与我的列表框不同。我发现实际上我并不需要选择元素的能力,因此将列表视图更改为itemscontrol解决了我的问题。
另请参见:

http://connect.microsoft.com/VisualStudio/feedback/details/750655/selected-listboxitem-does-not-have-a-background-of-controlbrushkey-when-app-is-unfocused


很好的发现,可惜该属性仅适用于 .net 4.5,而我正在针对 4.0 进行开发。我会关注该帖子并查看是否有其他解决方法,而不是强制所有客户端升级到 4.5。 - Oli
我修改了帖子,因为最后我终于找到了在.NET 4中完美运行的解决方案。希望它也能帮助您解决问题。 - Anders Rune Jensen

0

这是我想出来的一个解决方案,它不涉及更改系统颜色或控件模板。只需将ListBox包装在一个新的UserControl中。

public partial class StyledListBox : UserControl
{
    public DataTemplate ItemTemplate
    {
        get { return (DataTemplate)GetValue(ItemTemplateProperty); }
        set { SetValue(ItemTemplateProperty, value); }
    }

    public IEnumerable ItemsSource
    {
        get { return (IEnumerable)GetValue(ItemsSourceProperty); }
        set { SetValue(ItemsSourceProperty, value); }
    }

    public object SelectedItem
    {
        get { return GetValue(SelectedItemProperty); }
        set { SetValue(SelectedItemProperty, value); }
    }

    public StyledListBox()
    {
        InitializeComponent();
    }

    public static readonly DependencyProperty ItemTemplateProperty = DependencyProperty.Register("ItemTemplate", typeof(DataTemplate), typeof(StyledListBox), new FrameworkPropertyMetadata(null));
    public static readonly DependencyProperty ItemsSourceProperty = DependencyProperty.Register("ItemsSource", typeof(IEnumerable), typeof(StyledListBox), new FrameworkPropertyMetadata(null));

    public static readonly DependencyProperty SelectedItemProperty = DependencyProperty.Register("SelectedItem", typeof(object), typeof(StyledListBox), new FrameworkPropertyMetadata(null)
    {
        BindsTwoWayByDefault = true,
        DefaultUpdateSourceTrigger = UpdateSourceTrigger.PropertyChanged
    });
}

XAML:

<UserControl x:Class="StyledListBox"

     <ListBox ItemsSource="{Binding ItemsSource, RelativeSource={RelativeSource FindAncestor, AncestorType={x:Type common:StyledListBox}}}"
              SelectedItem="{Binding SelectedItem, RelativeSource={RelativeSource FindAncestor, AncestorType={x:Type common:StyledListBox}}}">

        <ListBox.ItemTemplate>
            <DataTemplate>
                <Border>
                    <Border.Style>
                        <Style TargetType="{x:Type Border}">
                            <Style.Triggers>
                                <DataTrigger Binding="{Binding IsSelected, UpdateSourceTrigger=PropertyChanged, RelativeSource={RelativeSource FindAncestor, AncestorType={x:Type ListBoxItem}}}"
                                             Value="True">
                                    <Setter Property="Background" Value="Red" />
                                </DataTrigger>
                            </Style.Triggers>
                        </Style>
                    </Border.Style>

                    <ContentPresenter ContentTemplate="{Binding ItemTemplate, RelativeSource={RelativeSource FindAncestor, AncestorType={x:Type StyledListBox}}}" />
                </Border>
            </DataTemplate>
        </ListBox.ItemTemplate>
    </ListBox>
</UserControl>

然后,只需像使用ListBox一样使用包装器UserControl。您想要控制的任何其他ListBox属性都可以以与我的示例中的ItemsSourceSelectedItem相同的方式添加到包装器中。


这会改变DataTemplate内边框的颜色,而不是整个行(与ListBox选择不同)...即使设置<Setter Property="HorizontalAlignment" Value="Stretch"/>也没有帮助... - Giacomo Pirinoli

0
<Style.Triggers>
                <Trigger Property="IsSelected" Value="true">
                    <Setter Property="Effect">
                        <Setter.Value>
                            <DropShadowEffect Color="Red"
                              BlurRadius="0"
                              ShadowDepth="0" />
                        </Setter.Value>
                    </Setter>
                </Trigger>

0

这被称为默认主题,它是系统相关的,你不应该去乱动它。你可以通过设置另一个Control.Template来完全覆盖它。


@Oli:刚才我说的话不算,整个主题往往不是一个好主意,可能会让一些用户感到烦恼。无论如何,您可以通过设置模板来更改外观,控件在每个系统上看起来都是相同的(除非您将其设置为依赖于系统)。 - H.B.
我已经定义了Listbox.ItemsPanel、Listbox.Template、Listbox.ItemTemplate和Listbox.itemcontainerstyle。它在我测试过的每个Windows版本上都可以工作,并且具有相同的视觉样式,但在Windows 8上不行。我错过了什么吗? - Oli
模板通常由模板化组件本身组成。也许现在在模板中使用的控件具有不同的模板。 - H.B.
我认为这是真的,或者至少使用的颜色画笔已经改变了。但我就是找不出到底是什么和在哪里?请记住,.net 4.5 更改了所有 .net 4 的程序集,因此任何东西都可能发生了改变。 - Oli
列出两个版本的所有 SystemColors.*Brush 并进行比较,怎么样? - H.B.

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接