Search code examples
c#user-controlssystemcolors

Is there a way to respond to a change of System colors at design time?


I've got a usercontrol (derived from ContainerControl) which I'm filling using a gradient. The first gradient color may or may not be a system color, like SystemColors.Highlight. The second gradient color is derived from the first one, by means of ControlPaint.Light(firstColor) or something similar.

I can easily handle changing system colors at runtime by overriding OnSystemColorsChanged, and it works without any trouble. But if the control is placed on a form at design time, and then the system colors are changed, the second color stays the same, probably due to OnSystemColorsChanged not being called at design time.

I can reset the second color manually since I provide ShouldSerialize- and Reset- methods for the second color property, and therefore the default value for that property changes accordingly when the system color changes.

So, is there any way to catch a system color change at design time?

Edit:

Here's a minimized code sample:

public class Test : ContainerControl
{

public Test()
{
  ResetColor1();
  ResetColor2();
}

private bool _resetColor2;


// Color 1 stuff
private Color _color1 = Color.Empty;
public System.Drawing.Color Color1
{
  get { return _color1; }
  set
  {
    _resetColor2 = !ShouldSerializeColor2();
    _color1 = value;
    if (_resetColor2)
      ResetColor2();
    Invalidate();
  }
}
// Defaults Color 1
private Color DefaultColor1 { get { return SystemColors.Highlight; } }
public bool ShouldSerializeColor1()
{
  return !Color1.Equals(Color.Empty) && !Color1.Equals(DefaultColor1);
}
public void ResetColor1()
{
  Color1 = DefaultColor1;
}

// Color 2 stuff
private Color _color2 = Color.Empty;
public System.Drawing.Color Color2
{
  get { return _color2; }
  set
  {
    _color2 = value;
    Invalidate();
  }
}
private Color DefaultColor2 { get { return ControlPaint.Light(Color1); } }
public bool ShouldSerializeColor2()
{
  return !Color2.Equals(DefaultColor2);
}
public void ResetColor2()
{
  Color2 = DefaultColor2;
}

protected override void OnPaint(PaintEventArgs e)
{
  base.OnPaint(e);
  using (LinearGradientBrush b = new LinearGradientBrush(ClientRectangle, Color1, Color2, LinearGradientMode.ForwardDiagonal))
    e.Graphics.FillRectangle(b, this.ClientRectangle);
}

protected override void OnSystemColorsChanged(EventArgs e)
{
  base.OnSystemColorsChanged(e);

  if (_resetColor2)
    ResetColor2();
}
}

If you put this control onto a form, this code will do the following:

  • Default Color1 to SystemColors.Highlight

  • Default Color2 to a lighter color

  • If Color2 is not changed manually, it will automatically derive from Color1

  • If system colors change at runtime, Color1 and Color2 will both change

  • If system colors change at design time, only Color1 will change


Solution

  • I wouldn't be too surprised if the event is suppressed in design mode, SystemEvents are tricky because they are static events. Solve your problem by setting a bool flag in the property setter for Color2 to indicate that it matches the default color. Always use ControlPaint.Light() when the flag is set.