Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
Expand Up @@ -32,9 +32,6 @@ internal sealed class ModernButtonDarkModeRenderer : ButtonDarkModeRendererBase
private static readonly Color s_darkNormal = Color.FromArgb(0x2D, 0x2D, 0x2D);
private static readonly Color s_darkNormalHover = Color.FromArgb(0x32, 0x32, 0x32);
private static readonly Color s_darkNormalPressed = Color.FromArgb(0x2A, 0x2A, 0x2A);
private static readonly Color s_darkDisabled = Color.FromArgb(0x25, 0x25, 0x25);

private static readonly Color s_darkDisabledText = Color.FromArgb(0x88, 0x88, 0x88);

private static readonly Color s_darkGap = Color.FromArgb(0x0A, 0x0A, 0x0A);
private static readonly Color s_darkFocusRing = Color.White;
Expand All @@ -43,11 +40,8 @@ internal sealed class ModernButtonDarkModeRenderer : ButtonDarkModeRendererBase
private static readonly Color s_lightNormal = Color.FromArgb(0xFB, 0xFB, 0xFB);
private static readonly Color s_lightNormalHover = Color.FromArgb(0xF9, 0xF9, 0xF9);
private static readonly Color s_lightNormalPressed = Color.FromArgb(0xF5, 0xF5, 0xF5);
private static readonly Color s_lightDisabled = Color.FromArgb(0xFA, 0xFA, 0xFA);
private static readonly Color s_lightBorder = Color.FromArgb(0xD0, 0xD0, 0xD0);

private static readonly Color s_lightDisabledText = Color.FromArgb(0xA0, 0xA0, 0xA0);

private static bool IsDark => Application.IsDarkModeEnabled;

private int FocusRingThickness
Expand Down Expand Up @@ -182,25 +176,16 @@ public override void DrawFocusIndicator(Graphics graphics, Rectangle bounds, boo

public override Color GetTextColor(PushButtonState state, bool isDefault, Color backColor)
{
if (state == PushButtonState.Disabled)
{
Color preferredForeColor = IsDark
? s_darkDisabledText
: s_lightDisabledText;

return ModernControlColorMath.GetDisabledTextColor(
preferredForeColor,
backColor);
}

return ModernButtonColorMath.GetReadableForeColor(backColor);
return state == PushButtonState.Disabled
? ModernControlColorMath.GetDisabledForeColor(backColor)
: ModernButtonColorMath.GetReadableForeColor(backColor);
}

public override Color GetBackgroundColor(PushButtonState state, bool isDefault)
{
if (state == PushButtonState.Disabled)
{
return IsDark ? s_darkDisabled : s_lightDisabled;
return ModernControlColorMath.GetDisabledSurfaceColor();
}

if (isDefault)
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -19,9 +19,7 @@ internal sealed class ModernFlatButtonRenderer : ButtonDarkModeRendererBase
private static readonly Color s_lightBorder = Color.FromArgb(0xD0, 0xD0, 0xD0);
private static readonly Color s_darkBorder = Color.FromArgb(0x55, 0x55, 0x55);
private static readonly Color s_lightNormal = Color.FromArgb(0xFB, 0xFB, 0xFB);
private static readonly Color s_lightDisabled = Color.FromArgb(0xFA, 0xFA, 0xFA);
private static readonly Color s_darkNormal = Color.FromArgb(0x2D, 0x2D, 0x2D);
private static readonly Color s_darkDisabled = Color.FromArgb(0x25, 0x25, 0x25);

private static bool IsDark => Application.IsDarkModeEnabled;

Expand Down Expand Up @@ -96,25 +94,16 @@ public override void DrawFocusIndicator(Graphics graphics, Rectangle contentBoun

public override Color GetTextColor(PushButtonState state, bool isDefault, Color backColor)
{
if (state == PushButtonState.Disabled)
{
Color preferredForeColor = IsDark
? Color.FromArgb(0x88, 0x88, 0x88)
: Color.FromArgb(0xA0, 0xA0, 0xA0);

return ModernControlColorMath.GetDisabledTextColor(
preferredForeColor,
backColor);
}

return ModernButtonColorMath.GetReadableForeColor(backColor);
return state == PushButtonState.Disabled
? ModernControlColorMath.GetDisabledForeColor(backColor)
: ModernButtonColorMath.GetReadableForeColor(backColor);
}

public override Color GetBackgroundColor(PushButtonState state, bool isDefault)
{
if (state == PushButtonState.Disabled)
{
return IsDark ? s_darkDisabled : s_lightDisabled;
return ModernControlColorMath.GetDisabledSurfaceColor();
}

if (isDefault)
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -139,10 +139,8 @@ private static void DrawStandardFrame(
Rectangle clientBounds,
Rectangle borderBounds)
{
Color background = GetEffectiveBackColor(comboBox);
Color borderColor = GetBorderColor(
comboBox,
background,
useAccent: false);

CutOutRoundedCorners(
Expand All @@ -166,10 +164,8 @@ private static void DrawFlatFrame(
return;
}

Color background = GetEffectiveBackColor(comboBox);
Color borderColor = GetBorderColor(
comboBox,
background,
useAccent: false);
using var pen = borderColor.GetCachedPenScope(
GetBorderThickness(comboBox));
Expand All @@ -182,10 +178,8 @@ private static void DrawPopupFrame(
Rectangle clientBounds,
Rectangle borderBounds)
{
Color background = GetEffectiveBackColor(comboBox);
Color borderColor = GetBorderColor(
comboBox,
background,
useAccent: true);
CutOutRoundedCorners(
comboBox,
Expand Down Expand Up @@ -223,9 +217,7 @@ private void DrawDropDownButton(
0.035f);
if (!comboBox.Enabled)
{
buttonColor = PopupButtonColorMath.Mute(
buttonColor,
0.55f);
buttonColor = ModernControlColorMath.GetDisabledSurfaceColor();
}

using (var brush = buttonColor.GetCachedSolidBrushScope())
Expand All @@ -235,9 +227,7 @@ private void DrawDropDownButton(

Color chevronColor = comboBox.Enabled
? PopupButtonColorMath.GetReadableForeColor(buttonColor)
: ModernControlColorMath.GetDisabledTextColor(
comboBox.ForeColor,
buttonColor);
: ModernControlColorMath.GetDisabledForeColor(buttonColor);
int halfWidth = Math.Max(
2,
ScaleHelper.ScaleToDpi(3, _deviceDpi));
Expand Down Expand Up @@ -316,9 +306,7 @@ private void DrawDropDownListText(
? comboBox.ForeColor
: PopupButtonColorMath.GetReadableForeColor(
background)
: ModernControlColorMath.GetDisabledTextColor(
comboBox.ForeColor,
background);
: ModernControlColorMath.GetDisabledForeColor(background);
TextFormatFlags flags = TextFormatFlags.SingleLine
| TextFormatFlags.VerticalCenter
| TextFormatFlags.EndEllipsis
Expand Down Expand Up @@ -421,20 +409,16 @@ private static void DrawRoundedBorder(
parentColor);
}

private static Color GetBorderColor(
ComboBox comboBox,
Color background,
bool useAccent)
private static Color GetBorderColor(ComboBox comboBox, bool useAccent)
{
Color borderColor = useAccent
if (!comboBox.Enabled)
{
return ModernControlColorMath.GetDisabledBorderColor();
}

return useAccent
? Application.SystemVisualSettings.AccentColor
: comboBox.ForeColor;

return comboBox.Enabled
? borderColor
: ModernControlColorMath.GetDisabledTextColor(
borderColor,
background);
}

private static int GetBorderThickness(ComboBox comboBox)
Expand Down Expand Up @@ -480,16 +464,13 @@ private static Color GetEffectiveBackColor(ComboBox comboBox)
?? SystemColors.Window;

/// <summary>
/// Returns the field surface color, muted when the ComboBox is disabled so a disabled
/// control no longer shows its full custom <see cref="Control.BackColor"/> (issue #14797).
/// Returns the field surface color. A disabled ComboBox does not honor user-set
/// <see cref="Control.BackColor"/> values and uses the shared modern disabled surface
/// instead, which adapts to the current color mode (issue #14797).
/// </summary>
private static Color GetEffectiveFieldColor(ComboBox comboBox)
{
Color background = GetEffectiveBackColor(comboBox);

return comboBox.Enabled
? background
: PopupButtonColorMath.Mute(background, 0.55f);
}
=> comboBox.Enabled
? GetEffectiveBackColor(comboBox)
: ModernControlColorMath.GetDisabledSurfaceColor();
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -3826,6 +3826,27 @@ protected override unsafe void WndProc(ref Message m)
return;
}

// Modern NET11 mode, disabled DropDown: the native edit child sends
// WM_CTLCOLORSTATIC and the OS default would produce a white background,
// inconsistent with the disabled surface ModernComboAdapter paints for the rest
// of the field. In light mode, explicitly set disabled colors via system values.
// In dark mode, ModernComboAdapter already renders the disabled surface correctly,
// and the edit child inherits appropriate rendering from the parent control.
if (hwndChild == _childEdit?.HWND
&& UsesModernComboAdapter
&& !Enabled
&& !Application.IsDarkModeEnabled)
{
PInvokeCore.SetBkColor(
(HDC)m.WParamInternal,
ColorTranslator.ToWin32(SystemColors.ButtonFace));
PInvokeCore.SetTextColor(
(HDC)m.WParamInternal,
ColorTranslator.ToWin32(SystemColors.GrayText));
m.ResultInternal = (LRESULT)(nint)PInvokeCore.GetSysColorBrush(SystemColors.ButtonFace);
return;
Comment thread
LeafShi1 marked this conversation as resolved.
}

// Additional handling for Simple style listbox when disabled
if (DropDownStyle == ComboBoxStyle.Simple
&& Application.IsDarkModeEnabled
Expand Down
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
// Licensed to the .NET Foundation under one or more agreements.
// Licensed to the .NET Foundation under one or more agreements.
// The .NET Foundation licenses this file to you under the MIT license.

using System.Drawing;
Expand All @@ -16,6 +16,50 @@ internal static class ModernControlColorMath
private const float DisabledMuteAmount = 0.45f;
private const int ContrastSearchIterations = 10;

// Shared disabled-state palette for modern renderers. Modern controls do not honor user-set
// BackColor/ForeColor while disabled, so these fixed surfaces replace them. This is the single
// source of truth: the modern Button renderers and the modern ComboBox adapter all read from
// here, so a disabled Button and a disabled ComboBox cannot drift apart.
private static readonly Color s_darkModeDisabledSurface = Color.FromArgb(0x25, 0x25, 0x25);
private static readonly Color s_lightModeDisabledSurface = Color.FromArgb(0xFA, 0xFA, 0xFA);
private static readonly Color s_darkModeDisabledBorder = Color.FromArgb(0x55, 0x55, 0x55);
private static readonly Color s_lightModeDisabledBorder = Color.FromArgb(0xD0, 0xD0, 0xD0);
private static readonly Color s_darkModeDisabledForeground = Color.FromArgb(0x88, 0x88, 0x88);
private static readonly Color s_lightModeDisabledForeground = Color.FromArgb(0xA0, 0xA0, 0xA0);

/// <summary>
/// Gets the surface color for a disabled modern control, honoring the current color mode
/// and high contrast settings.
/// </summary>
internal static Color GetDisabledSurfaceColor()
=> SystemInformation.HighContrast
? SystemColors.Control
: Application.IsDarkModeEnabled
? s_darkModeDisabledSurface
: s_lightModeDisabledSurface;

/// <summary>
/// Gets the border color for a disabled modern control, honoring the current color mode
/// and high contrast settings.
/// </summary>
internal static Color GetDisabledBorderColor()
=> SystemInformation.HighContrast
? SystemColors.GrayText
: Application.IsDarkModeEnabled
? s_darkModeDisabledBorder
: s_lightModeDisabledBorder;

/// <summary>
/// Gets the contrast-adjusted foreground color for content drawn on
/// <see cref="GetDisabledSurfaceColor"/>.
/// </summary>
internal static Color GetDisabledForeColor(Color backColor)
=> GetDisabledTextColor(
Application.IsDarkModeEnabled
? s_darkModeDisabledForeground
: s_lightModeDisabledForeground,
backColor);

internal static Color GetDisabledTextColor(
Color preferredForeColor,
Color backColor)
Expand Down
Loading