0

I have here my customized ComboBox:

enter image description here

It's actually a browser selection. But right now what you see there is a prototype of the selector control using ComboBox.

The problem I am having is this dropdown (Popup) control background

enter image description here

The background color should dynamically change once the user change their theme color in Color and Apperance setting in Personalization.

This is the story behind my template

I am able to change the Background color using a simple Converter:

public object Convert(object value, Type targetType, object parameter, System.Globalization.CultureInfo culture)
{
    int argbColor = (int)Microsoft.Win32.Registry.GetValue(@"HKEY_CURRENT_USER\Software\Microsoft\Windows\DWM", "ColorizationColor", null);
    var color = System.Drawing.Color.FromArgb(argbColor);

    SolidColorBrush scb = new SolidColorBrush();

    if (Environment.OSVersion.Version.Major == 6 && Environment.OSVersion.Version.Minor == 1) // Windows 7
    {
        //scb = new SolidColorBrush(Color.FromArgb((byte)((int)color.A / 3), color.R, color.G, color.B));
        scb = new SolidColorBrush(Color.FromArgb(color.A, color.R, color.G, color.B));
    }
    else if (Environment.OSVersion.Version.Major == 6 && Environment.OSVersion.Version.Minor == 2) // Windows 8 
    {
        scb = new SolidColorBrush(Color.FromArgb(color.A, color.R, color.G, color.B));
    }

    return scb;
}

set it up like this:

<me:BackgroundConverter x:Key="BgConverter" />

and implement it like this:

<ControlTemplate TargetType="{x:Type ComboBox}">
    <Grid x:Name="MainGrid" SnapsToDevicePixels="true">
        <Grid.ColumnDefinitions>
            <ColumnDefinition Width="*"/>
            <ColumnDefinition MinWidth="{DynamicResource {x:Static SystemParameters.VerticalScrollBarWidthKey}}" Width="0"/>
        </Grid.ColumnDefinitions>
        <Popup x:Name="PART_Popup" Grid.Column="0" AllowsTransparency="true" IsOpen="{Binding IsDropDownOpen, RelativeSource={RelativeSource TemplatedParent}}" Margin="1" PopupAnimation="{DynamicResource {x:Static SystemParameters.ComboBoxPopupAnimationKey}}" Placement="Bottom">
            <Themes:SystemDropShadowChrome x:Name="Shdw" Color="Transparent">
                <Border x:Name="DropDownBorder" 
                    BorderBrush="{DynamicResource {x:Static SystemColors.WindowFrameBrushKey}}" 
                    BorderThickness="{Binding Converter={StaticResource BorderConverter}}" 
                    Background="{Binding Converter={StaticResource BgConverter}}" 
                    CornerRadius="0,0,12,12">

                    <ItemsPresenter x:Name="bn" KeyboardNavigation.DirectionalNavigation="Contained" SnapsToDevicePixels="{TemplateBinding SnapsToDevicePixels}" HorizontalAlignment="Center" />
                </Border>
            </Themes:SystemDropShadowChrome>
        </Popup>
        <ToggleButton Grid.ColumnSpan="2" IsChecked="{Binding IsDropDownOpen, Mode=TwoWay, RelativeSource={RelativeSource TemplatedParent}}" Style="{StaticResource ComboBoxReadonlyToggleButton}"/>
        <ContentPresenter ContentTemplate="{TemplateBinding SelectionBoxItemTemplate}" ContentTemplateSelector="{TemplateBinding ItemTemplateSelector}" Content="{TemplateBinding SelectionBoxItem}" ContentStringFormat="{TemplateBinding SelectionBoxItemStringFormat}" HorizontalAlignment="{TemplateBinding HorizontalContentAlignment}" IsHitTestVisible="false" Margin="{TemplateBinding Padding}" SnapsToDevicePixels="{TemplateBinding SnapsToDevicePixels}" VerticalAlignment="{TemplateBinding VerticalContentAlignment}"/>
    </Grid>
    <ControlTemplate.Triggers>
        <Trigger Property="HasItems" Value="false">
            <Setter Property="Height" TargetName="DropDownBorder" Value="95"/>
        </Trigger>
        <Trigger Property="IsEnabled" Value="false">
            <Setter Property="Foreground" Value="{DynamicResource {x:Static SystemColors.GrayTextBrushKey}}"/>
            <Setter Property="Background" Value="#FFF4F4F4"/>
        </Trigger>
        <Trigger Property="IsGrouping" Value="true">
            <Setter Property="ScrollViewer.CanContentScroll" Value="false"/>
        </Trigger>
    </ControlTemplate.Triggers>
</ControlTemplate>

check the Border x:Name="DropDownBorder" line. Now how do I make it dynamically change when a user changes their theme color? I tried via Trigger:

<Trigger Property="IsDropDownOpen" Value="true">
    <!-- not really working -->
    <Setter Property="Background" TargetName="DropDownBorder" Value="{Binding Converter={StaticResource BgConverter}}"/>
</Trigger>

but it's not working

I actually have a pretty simple lame solution by hooking onto DropDownOpened or DropDownClosed events and just change the background color from there. That solution is actually working pretty well but there may be a simplest way of doing it via Trigger or EventTrigger?

-- UPDATE --

public static class ComboBoxExtension
{
    public static void UpdatePopupBackground(this ComboBox cb)
    {
        Border b = (Border)cb.Template.FindName("DropDownBorder", cb);

        int argbColor = (int)Microsoft.Win32.Registry.GetValue(@"HKEY_CURRENT_USER\Software\Microsoft\Windows\DWM", "ColorizationColor", null);
        var color = System.Drawing.Color.FromArgb(argbColor);

        SolidColorBrush scb = new SolidColorBrush();

        if (Environment.OSVersion.Version.Major == 6 && Environment.OSVersion.Version.Minor == 1) // Windows 7
        {
            //scb = new SolidColorBrush(Color.FromArgb((byte)((int)color.A / 3), color.R, color.G, color.B));
            scb = new SolidColorBrush(Color.FromArgb(color.A, color.R, color.G, color.B));
        }
        else if (Environment.OSVersion.Version.Major == 6 && Environment.OSVersion.Version.Minor == 2) // Windows 8 
        {
            scb = new SolidColorBrush(Color.FromArgb(color.A, color.R, color.G, color.B));
        }

        b.Background = scb;
    }
}

and call it when the DropDownOpened triggers:

ComboMe.UpdatePopupBackground();

LOL... well..

Anatoliy Nikolaev
  • 22,370
  • 15
  • 69
  • 68
Jayson Ragasa
  • 1,011
  • 4
  • 19
  • 33

1 Answers1

0

It seems to me that the first step to get notified of this particular color change, you'll need to hook the WindowProc in MainWindow (or a hidden color-change-detection window?) and watch for the WM_DWMCOLORIZATIONCOLORCHANGED message from the DWM.

jschroedl
  • 4,916
  • 3
  • 31
  • 46