Переопределение цвета фона ListBoxItem, когда он не в фокусе (.NET 4.5)

Согласно этому переопределение ресурса ControlBrushKey должно изменить цвет фона выбранного элемента ListBox, когда он не имеет фокуса. Я создал простой пример, чтобы опровергнуть это:

 <StackPanel>
    <ListBox>
      <ListBox.Resources>
        <SolidColorBrush x:Key="{x:Static SystemColors.HighlightBrushKey}" Color="LightBlue"/>
        <!--SelectedItem without focus but doesn't really work-->
        <SolidColorBrush x:Key="{x:Static SystemColors.ControlBrushKey}" Color="Orange" />
      </ListBox.Resources>
      <ListBoxItem>
        Item 1
      </ListBoxItem>
      <ListBoxItem>
        Item 2
      </ListBoxItem>
    </ListBox>
    <TextBox></TextBox>
  </StackPanel>

Если вы запустите это в .NET 4.5, вы увидите, что он меняет только цвет в фокусе, но не в фокусе (это работает в .NET 4.0). Есть идеи, почему?

Изменить: похоже, это дубликат List/ Фон поля со списком и выбранные цвета в .net 4.5.


person Doron Yaacoby    schedule 03.10.2012    source источник
comment
возможный дубликат List/ComboBox Background And Selected Цвета в .net 4.5   -  person Doron Yaacoby    schedule 03.10.2012


Ответы (4)


Попробуйте следующее, чтобы изменить цвет фона выбранного ListBoxItem, когда он потерял фокус:

XAML

<ListBox.Resources>    
    <SolidColorBrush x:Key="{x:Static SystemColors.HighlightBrushKey}" Color="LightBlue"/> 
    <SolidColorBrush x:Key="{x:Static SystemColors.InactiveSelectionHighlightBrushKey }" Color="Orange" />    
</ListBox.Resources>

C#

listBox.Resources.Add(SystemColors.InactiveSelectionHighlightBrushKey, 
                      new SolidColorBrush(Colors.Orange));

Я надеюсь, что это работает для вас.

person Community    schedule 17.04.2013
comment
См. мой ответ для решения, которое не требует изменения SystemColors. - person bugged87; 30.01.2015

Все дело в шаблонах по умолчанию элементы управления, если они не используют системные цвета, как в .NET 4, это просто ничего не изменит.

person H.B.    schedule 03.10.2012
comment
Разве это не кардинальное изменение? И в любом случае похоже, что ControlBrushKey все еще используется. - person Doron Yaacoby; 03.10.2012
comment
@DoronYaacoby: это не критическое изменение, потому что полагаться на что-либо в шаблоне управления глупо. Это немного похоже на вызов приватных методов через отражение. - person H.B.; 03.10.2012
comment
Поскольку это принятый и получивший наибольшее количество голосов ответ на этот вопрос, я предполагаю, что очень многие люди сочли это решение самым простым, поэтому оно сломает множество приложений. Но в любом случае, как правильно достичь того, чего я хочу? - person Doron Yaacoby; 03.10.2012
comment
@DoronYaacoby: определите свой собственный шаблон. - person H.B.; 03.10.2012
comment
Разве это не перебор? Я просто хочу изменить пару цветов, я не хочу копировать и вставлять, а затем поддерживать огромный блок xaml. - person Doron Yaacoby; 03.10.2012
comment
@DoronYaacoby: Что ж, в этом отношении архитектура не так уж хороша, если бы было свойство ColorScheme, которое можно было бы настроить, это было бы здорово, но, поскольку это не так, перезапись всего шаблона - единственный действительно чистый вариант. - person H.B.; 03.10.2012

Вот что я придумал, что не связано с изменением системных цветов или шаблонов элементов управления. Просто оберните 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>

Затем просто используйте оболочку UserControl, как если бы это был ListBox. Любые другие свойства ListBox, которыми вы хотите управлять, можно просто добавить в оболочку таким же образом, как ItemsSource и SelectedItem из моего примера.

person bugged87    schedule 30.01.2015

Решением этого является добавление

FrameworkCompatibilityPreferences.AreInactiveSelectionHighlightBrushKeysSupported = false;

прежде чем звонить

InitializeComponent();
person Daniel    schedule 18.09.2013
comment
Выдает исключение: свойство «AreInactiveSelectionHighlightBrushKeysSupported» не может быть изменено. Класс FrameworkCompatibilityPreferences запечатан. - person bugged87; 30.01.2015
comment
@bugged87 добавьте это внутрь блока try/catch. Мои программы используют это, и все выглядит так, как задумано во всех версиях Windows. - person Daniel; 30.01.2015
comment
Конечно, добавление try/catch обрабатывает исключение, но этот код, похоже, не заставляет работать код OP. Я использую .NET 4.5 в Windows 8.1. - person bugged87; 30.01.2015