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
99 changes: 79 additions & 20 deletions src/System.Windows.Forms/System/Windows/Forms/Control.cs
Original file line number Diff line number Diff line change
Expand Up @@ -899,10 +899,10 @@ public virtual partial VisualStylesMode VisualStylesMode

VisualStylesMode oldEffectiveValue = EffectiveVisualStylesMode;

// Inherit was requested explicitly, or the requested value matches the ambient (parent) value:
// Inherit was requested explicitly, or the requested value matches the uncoerced ambient value:
// drop any local override so the value is inherited again.
if (value == VisualStylesMode.Inherit
|| (ParentInternal is { } parent && parent.ResolvedVisualStylesMode == value))
|| (ParentInternal is { } parent && parent.UncoercedVisualStylesMode == value))
{
Properties.RemoveValue(s_visualStylesModeProperty);
}
Expand All @@ -927,18 +927,30 @@ private bool ShouldSerializeVisualStylesMode()
private void ResetVisualStylesMode()
=> VisualStylesMode = VisualStylesMode.Inherit;

private VisualStylesMode ResolvedVisualStylesMode
private VisualStylesMode UncoercedVisualStylesMode
{
get
{
VisualStylesMode value = VisualStylesMode;

return value == VisualStylesMode.Inherit
? ParentInternal?.ResolvedVisualStylesMode ?? DefaultVisualStylesMode
? ParentInternal?.UncoercedVisualStylesMode ?? DefaultVisualStylesMode
: value;
}
}

private VisualStylesMode ResolvedVisualStylesMode
=> GetSupportedVisualStylesMode(
VisualStylesMode == VisualStylesMode.Inherit
? ParentInternal?.ResolvedVisualStylesMode ?? DefaultVisualStylesMode
: VisualStylesMode);

/// <summary>
/// Coerces a requested visual styles mode to one supported by this control.
/// </summary>
private protected virtual VisualStylesMode GetSupportedVisualStylesMode(VisualStylesMode mode)
=> mode;

/// <summary>
/// Gets the renderer-authoritative <see cref="Forms.VisualStylesMode"/> that controls must honor when deciding
/// <see cref="CreateParams"/> or paint behavior, after applying the High Contrast and disabled clamps.
Expand Down Expand Up @@ -7446,28 +7458,60 @@ protected virtual void OnParentVisualStylesModeChanged(EventArgs e)
return;
}

VisualStylesModeChangeEventArgs? transition = e as VisualStylesModeChangeEventArgs;
if (transition is not null
&& (!transition.IsCurrent
|| ParentInternal?.EffectiveVisualStylesMode != transition.NewEffectiveVisualStylesMode))
{
return;
}

if (Properties.ContainsKey(s_visualStylesModeProperty))
{
if (Properties.GetValueOrDefault<VisualStylesMode>(s_visualStylesModeProperty)
== ParentInternal?.ResolvedVisualStylesMode)
!= ParentInternal?.UncoercedVisualStylesMode)
{
Comment thread
SimonZhao888 marked this conversation as resolved.
// Same as the parent value, make it ambient again by removing it.
Properties.RemoveValue(s_visualStylesModeProperty);
// A local value isolates this subtree from parent changes.
return;
}

VisualStylesMode oldEffectiveVisualStylesMode = EffectiveVisualStylesMode;

// Same as the parent value, make it ambient again by removing it.
Properties.RemoveValue(s_visualStylesModeProperty);

VisualStylesMode newEffectiveVisualStylesMode = EffectiveVisualStylesMode;
if (oldEffectiveVisualStylesMode == newEffectiveVisualStylesMode)
{
return;
}

// A local value isolates this subtree from parent changes. If the local value matched the
// parent's new value, removing it preserves the effective value while making it ambient again.
OnVisualStylesModeChanged(
transition?.CreateForControl(
this,
oldEffectiveVisualStylesMode,
newEffectiveVisualStylesMode)
?? e);

return;
}

if (e is VisualStylesModeChangeEventArgs transition
&& (!transition.IsCurrent
|| ParentInternal?.EffectiveVisualStylesMode != transition.NewEffectiveVisualStylesMode))
if (transition is not null)
{
VisualStylesModeChangeEventArgs transitionForControl = transition.CreateForControl(this);
if (transitionForControl.OldEffectiveVisualStylesMode
!= transitionForControl.NewEffectiveVisualStylesMode)
{
OnVisualStylesModeChanged(transitionForControl);
}
else if (ChildControls is { } children)
{
CascadeVisualStylesModeChanged(children, transitionForControl, transitionForControl);
}

return;
}

// In every other case we're going to raise the event.
OnVisualStylesModeChanged(e);
}

Expand Down Expand Up @@ -7534,19 +7578,34 @@ public bool IsCurrent

public VisualStylesModeChangeEventArgs CreateForControl(Control control)
{
if (SystemVisualSettingsTransition is not { } systemVisualSettingsTransition)
if (SystemVisualSettingsTransition is { } systemVisualSettingsTransition)
{
return this;
return new(
_state,
control,
control.Properties.GetValueOrDefault(s_visualStylesModeChangeVersionProperty, 0),
control.GetEffectiveVisualStylesMode(systemVisualSettingsTransition.OldSettings.HighContrastEnabled),
control.GetEffectiveVisualStylesMode(systemVisualSettingsTransition.NewSettings.HighContrastEnabled),
systemVisualSettingsTransition);
}

return new(
return CreateForControl(
control,
control.GetSupportedVisualStylesMode(OldEffectiveVisualStylesMode),
control.GetSupportedVisualStylesMode(NewEffectiveVisualStylesMode));
}

public VisualStylesModeChangeEventArgs CreateForControl(
Control control,
VisualStylesMode oldEffectiveVisualStylesMode,
VisualStylesMode newEffectiveVisualStylesMode)
=> new(
_state,
control,
control.Properties.GetValueOrDefault(s_visualStylesModeChangeVersionProperty, 0),
control.GetEffectiveVisualStylesMode(systemVisualSettingsTransition.OldSettings.HighContrastEnabled),
control.GetEffectiveVisualStylesMode(systemVisualSettingsTransition.NewSettings.HighContrastEnabled),
systemVisualSettingsTransition);
}
oldEffectiveVisualStylesMode,
newEffectiveVisualStylesMode,
systemVisualSettingsTransition: null);

public void PerformLayouts()
{
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -16,6 +16,9 @@ namespace System.Windows.Forms;
[SRDescription(nameof(SR.DescriptionDataGridView))]
public partial class DataGridView : Control, ISupportInitialize
{
private protected override VisualStylesMode GetSupportedVisualStylesMode(VisualStylesMode mode)
=> mode >= VisualStylesMode.Net11 ? VisualStylesMode.Classic : mode;

private static readonly object s_allowUserToAddRowsChangedEvent = new();
private static readonly object s_allowUserToDeleteRowsChangedEvent = new();
private static readonly object s_allowUserToOrderColumnsChangedEvent = new();
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -23,6 +23,9 @@ namespace System.Windows.Forms;
[DefaultEvent(nameof(ItemClicked))]
public partial class ToolStrip : ScrollableControl, IArrangedElement, ISupportToolStripPanel
{
private protected override VisualStylesMode GetSupportedVisualStylesMode(VisualStylesMode mode)
=> mode >= VisualStylesMode.Net11 ? VisualStylesMode.Classic : mode;

private static Size s_onePixel = new(1, 1);
internal static Point s_invalidMouseEnter = new(int.MaxValue, int.MaxValue);

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -496,6 +496,33 @@ public void Control_VisualStylesMode_ReentrantChange_SuppressesStaleChildCascade
Assert.Equal(1, childChangedCallCount);
}

[WinFormsFact]
public void Control_VisualStylesMode_LocalOverrideRemovedByCoercedParent_RaisesChangedAndCascades()
{
using DataGridView parent = new() { VisualStylesMode = VisualStylesMode.Disabled };
using SubControlWithVisualStyles child = new()
{
HighContrast = false,
VisualStylesMode = VisualStylesMode.Latest
};
using SubControlWithVisualStyles grandchild = new() { HighContrast = false };
child.Controls.Add(grandchild);
parent.Controls.Add(child);

int childChangedCallCount = 0;
child.VisualStylesModeChanged += (sender, e) => childChangedCallCount++;
int grandchildChangedCallCount = 0;
grandchild.VisualStylesModeChanged += (sender, e) => grandchildChangedCallCount++;

parent.VisualStylesMode = VisualStylesMode.Latest;

Assert.Equal(VisualStylesMode.Inherit, child.VisualStylesMode);
Assert.Equal(VisualStylesMode.Classic, child.EffectiveVisualStylesModeAccessor);
Assert.Equal(VisualStylesMode.Classic, grandchild.EffectiveVisualStylesModeAccessor);
Assert.Equal(1, childChangedCallCount);
Assert.Equal(1, grandchildChangedCallCount);
}

[WinFormsFact]
public void Appearance_ToggleSwitch_HasExpectedValue()
{
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -38,6 +38,61 @@ public void DataGridView_Ctor_Default()
Assert.Same(control.RowTemplate, control.RowTemplate);
}

[WinFormsTheory]
[InlineData(VisualStylesMode.Net11)]
[InlineData(VisualStylesMode.Latest)]
public void DataGridView_VisualStylesMode_ModernMode_UsesClassicEffectiveMode(VisualStylesMode value)
{
using SubDataGridView control = new() { VisualStylesMode = value };

Assert.Equal(value, control.VisualStylesMode);
Assert.Equal(VisualStylesMode.Classic, control.EffectiveVisualStylesModeAccessor);
Assert.False(control.IsHandleCreated);
}

[WinFormsTheory]
[InlineData(VisualStylesMode.Net11)]
[InlineData(VisualStylesMode.Latest)]
public void DataGridView_VisualStylesMode_InheritedModernMode_UsesClassicEffectiveMode(VisualStylesMode value)
{
using Control parent = new() { VisualStylesMode = value };
using SubDataGridView control = new();
parent.Controls.Add(control);

Assert.Equal(VisualStylesMode.Inherit, control.VisualStylesMode);
Assert.Equal(VisualStylesMode.Classic, control.EffectiveVisualStylesModeAccessor);
Assert.False(control.IsHandleCreated);
}

[WinFormsFact]
public void DataGridView_VisualStylesMode_ParentChangesToModernMode_DoesNotRaiseChanged()
{
using Control parent = new() { VisualStylesMode = VisualStylesMode.Classic };
using SubDataGridView control = new();
parent.Controls.Add(control);
int callCount = 0;
control.VisualStylesModeChanged += (sender, e) => callCount++;

parent.VisualStylesMode = VisualStylesMode.Net11;

Assert.Equal(VisualStylesMode.Classic, control.EffectiveVisualStylesModeAccessor);
Assert.Equal(0, callCount);
}

[WinFormsFact]
public void DataGridView_VisualStylesMode_ExplicitClassic_RemainsLocalOverride()
{
using Control parent = new() { VisualStylesMode = VisualStylesMode.Net11 };
using SubDataGridView control = new();
parent.Controls.Add(control);
control.VisualStylesMode = VisualStylesMode.Classic;

parent.VisualStylesMode = VisualStylesMode.Disabled;

Assert.Equal(VisualStylesMode.Classic, control.VisualStylesMode);
Assert.Equal(VisualStylesMode.Classic, control.EffectiveVisualStylesModeAccessor);
}

private const int DefaultColumnHeadersHeight = 23;

public static IEnumerable<object[]> ColumnHeadersHeight_Set_TestData()
Expand Down Expand Up @@ -2892,6 +2947,8 @@ private class SubDataGridViewCell : DataGridViewCell

private class SubDataGridView : DataGridView
{
public VisualStylesMode EffectiveVisualStylesModeAccessor => base.EffectiveVisualStylesMode;

public new void OnColumnHeadersHeightChanged(EventArgs e) => base.OnColumnHeadersHeightChanged(e);

public new void OnColumnHeadersHeightSizeModeChanged(DataGridViewAutoSizeModeEventArgs e) => base.OnColumnHeadersHeightSizeModeChanged(e);
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -16,6 +16,61 @@ namespace System.Windows.Forms.Tests;

public partial class ToolStripTests : IDisposable
{
[WinFormsTheory]
[InlineData(VisualStylesMode.Net11)]
[InlineData(VisualStylesMode.Latest)]
public void ToolStrip_VisualStylesMode_ModernMode_UsesClassicEffectiveMode(VisualStylesMode value)
{
using SubToolStrip control = new() { VisualStylesMode = value };

Assert.Equal(value, control.VisualStylesMode);
Assert.Equal(VisualStylesMode.Classic, control.EffectiveVisualStylesModeAccessor);
Assert.False(control.IsHandleCreated);
}

[WinFormsTheory]
[InlineData(VisualStylesMode.Net11)]
[InlineData(VisualStylesMode.Latest)]
public void ToolStrip_VisualStylesMode_InheritedModernMode_UsesClassicEffectiveMode(VisualStylesMode value)
{
using Control parent = new() { VisualStylesMode = value };
using SubToolStrip control = new();
parent.Controls.Add(control);

Assert.Equal(VisualStylesMode.Inherit, control.VisualStylesMode);
Assert.Equal(VisualStylesMode.Classic, control.EffectiveVisualStylesModeAccessor);
Assert.False(control.IsHandleCreated);
}

[WinFormsFact]
public void ToolStrip_VisualStylesMode_ParentChangesToModernMode_DoesNotRaiseChanged()
{
using Control parent = new() { VisualStylesMode = VisualStylesMode.Classic };
using SubToolStrip control = new();
parent.Controls.Add(control);
int callCount = 0;
control.VisualStylesModeChanged += (sender, e) => callCount++;

parent.VisualStylesMode = VisualStylesMode.Net11;

Assert.Equal(VisualStylesMode.Classic, control.EffectiveVisualStylesModeAccessor);
Assert.Equal(0, callCount);
}

[WinFormsFact]
public void ToolStrip_VisualStylesMode_ExplicitClassic_RemainsLocalOverride()
{
using Control parent = new() { VisualStylesMode = VisualStylesMode.Net11 };
using SubToolStrip control = new();
parent.Controls.Add(control);
control.VisualStylesMode = VisualStylesMode.Classic;

parent.VisualStylesMode = VisualStylesMode.Disabled;

Assert.Equal(VisualStylesMode.Classic, control.VisualStylesMode);
Assert.Equal(VisualStylesMode.Classic, control.EffectiveVisualStylesModeAccessor);
}

[WinFormsFact]
public void ToolStrip_Ctor_Default()
{
Expand Down Expand Up @@ -7537,6 +7592,8 @@ public SubToolStrip(ToolStripItem[] items) : base(items)

public new bool CanRaiseEvents => base.CanRaiseEvents;

public VisualStylesMode EffectiveVisualStylesModeAccessor => base.EffectiveVisualStylesMode;

public new CreateParams CreateParams => base.CreateParams;

public new Cursor DefaultCursor => base.DefaultCursor;
Expand Down