Skip to content
Open
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 @@ -89,7 +89,7 @@ internal override Size GetPreferredSizeCore(Size proposedSize)
{
if (Control.Appearance == Appearance.Button)
{
ButtonStandardAdapter adapter = new(Control);
ButtonBaseAdapter adapter = DarkModeAdapterFactory.CreateStandardAdapter(Control);
return adapter.GetPreferredSizeCore(proposedSize);
}
else
Expand All @@ -105,9 +105,9 @@ internal override Size GetPreferredSizeCore(Size proposedSize)
}
}

private new ButtonStandardAdapter ButtonAdapter => (ButtonStandardAdapter)base.ButtonAdapter;
private new ButtonBaseAdapter ButtonAdapter => base.ButtonAdapter;

protected override ButtonBaseAdapter CreateButtonAdapter() => new ButtonStandardAdapter(Control);
protected override ButtonBaseAdapter CreateButtonAdapter() => DarkModeAdapterFactory.CreateStandardAdapter(Control);

Comment on lines 109 to 111
protected override LayoutOptions Layout(PaintEventArgs e)
{
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -158,22 +158,28 @@ internal override void PaintOver(PaintEventArgs e, CheckState state)
g.SmoothingMode = Drawing.Drawing2D.SmoothingMode.AntiAlias;

LayoutData layout = CommonLayout().Layout();

// A checked toggle-button must remain visually pressed even on hover.
PushButtonState pushButtonState = state == CheckState.Checked
? PushButtonState.Pressed
: PushButtonState.Hot;

ButtonDarkModeRenderer.RenderButton(
g,
Control.ClientRectangle,
Control.FlatStyle,
PushButtonState.Hot,
pushButtonState,
Control.IsDefault,
Control.Focused,
Control.ShowFocusCues,
Control.Parent?.BackColor ?? Control.BackColor,
GetButtonBackColor(PushButtonState.Hot),
GetButtonBackColor(pushButtonState),
_ => PaintImage(e, layout),
() => PaintField(
e,
layout,
PaintDarkModeRender(e).Calculate(),
GetButtonTextColor(e, PushButtonState.Hot),
GetButtonTextColor(e, pushButtonState),
drawFocus: false)
);

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -50,9 +50,9 @@ internal override void PaintOver(PaintEventArgs e, CheckState state)
}
}

private new ButtonStandardAdapter ButtonAdapter => (ButtonStandardAdapter)base.ButtonAdapter;
private new ButtonBaseAdapter ButtonAdapter => base.ButtonAdapter;

protected override ButtonBaseAdapter CreateButtonAdapter() => new ButtonStandardAdapter(Control);
protected override ButtonBaseAdapter CreateButtonAdapter() => DarkModeAdapterFactory.CreateStandardAdapter(Control);

Comment on lines +53 to 56
protected override LayoutOptions Layout(PaintEventArgs e)
{
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -96,17 +96,7 @@ public Appearance Appearance
}
}

private protected override bool OwnerDraw =>
// We want NO owner draw ONLY when we're
// * In Dark Mode
// * When _then_ the Appearance is Button
// * But then ONLY when we're rendering with FlatStyle.Standard
// (because that would let us usually let us draw with the VisualStyleRenderers,
// which cause HighDPI issues in Dark Mode).
(!Application.IsDarkModeEnabled
|| Appearance != Appearance.Button
|| FlatStyle != FlatStyle.Standard)
&& base.OwnerDraw;
private protected override bool OwnerDraw => base.OwnerDraw;

[SRCategory(nameof(SR.CatPropertyChanged))]
[SRDescription(nameof(SR.CheckBoxOnAppearanceChangedDescr))]
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -173,18 +173,7 @@ public bool Checked
}
}

private protected override bool OwnerDraw =>
// Order is key here - do NOT change!
// We want NO owner draw ONLY when we're
// * in Dark Mode
// * when _then_ the Appearance is Button
// * but then ONLY when we're rendering with FlatStyle.Standard
// (because that would let us usually let us draw with the VisualStyleRenderers,
// which cause HighDPI issues in Dark Mode).
(!Application.IsDarkModeEnabled
|| Appearance != Appearance.Button
|| FlatStyle != FlatStyle.Standard)
&& base.OwnerDraw;
private protected override bool OwnerDraw => base.OwnerDraw;

Comment on lines +176 to 177
/// <hideinheritance/>
[Browsable(false)]
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -631,6 +631,31 @@ public void CheckBox_ToStringTest()
Assert.Equal(expected, actual);
}

#pragma warning disable SYSLIB5002 // Type is for evaluation purposes only and is subject to change or removal in future updates.
[WinFormsFact]
public void CheckBox_OwnerDraw_AppearanceButton_FlatStyleStandard_InDarkMode_IsTrue()
{
// Regression test for https://github.com/dotnet/winforms/issues/14347:
// CheckBox with Appearance.Button + FlatStyle.Standard must always use owner-draw,
// including in dark mode. If OwnerDraw returns false the control falls back to
// native ComCtl32 painting which renders an invisible button on dark backgrounds.
Application.SetColorMode(SystemColorMode.Dark);
try
{
using SubCheckBox control = new()
{
Appearance = Appearance.Button,
FlatStyle = FlatStyle.Standard
};
Assert.True(control.GetStyle(ControlStyles.UserPaint));
}
finally
{
Application.SetColorMode(SystemColorMode.Classic);
}
}
#pragma warning restore SYSLIB5002

public class SubCheckBox : CheckBox
{
public new bool CanEnableIme => base.CanEnableIme;
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -1665,5 +1665,30 @@ internal override bool RaiseAutomationPropertyChangedEvent(UIA_PROPERTY_ID prope
[InlineData(Appearance.Normal, FlatStyle.System)]
public void RadioButton_OverChangeRectangle_Get(Appearance appearance, FlatStyle flatStyle) => base.ButtonBase_OverChangeRectangle_Get(appearance, flatStyle);

#pragma warning disable SYSLIB5002 // Type is for evaluation purposes only and is subject to change or removal in future updates.
[WinFormsFact]
public void RadioButton_OwnerDraw_AppearanceButton_FlatStyleStandard_InDarkMode_IsTrue()
{
// Regression test for https://github.com/dotnet/winforms/issues/14347:
// RadioButton with Appearance.Button + FlatStyle.Standard must always use owner-draw,
// including in dark mode. If OwnerDraw returns false the control falls back to
// native ComCtl32 painting which renders an invisible button on dark backgrounds.
Application.SetColorMode(SystemColorMode.Dark);
try
{
using SubRadioButton control = new()
{
Appearance = Appearance.Button,
FlatStyle = FlatStyle.Standard
};
Assert.True(control.GetStyle(ControlStyles.UserPaint));
}
finally
{
Application.SetColorMode(SystemColorMode.Classic);
}
}
#pragma warning restore SYSLIB5002

protected override ButtonBase CreateButton() => new SubRadioButton();
}