有没有办法在设计时响应系统颜色的变化?
我有一个用户控件(源自 ContainerControl),我使用渐变填充它。第一个渐变颜色可能是也可能不是系统颜色,例如 SystemColors.Highlight。 第二个渐变颜色是通过 ControlPaint.Light(firstColor) 或类似方法从第一个渐变颜色派生出来的。
我可以通过重写 OnSystemColorsChanged
轻松处理运行时系统颜色的变化,并且它的工作没有任何问题。但是,如果在设计时将控件放置在窗体上,然后更改系统颜色,则第二个颜色保持不变,这可能是由于在设计时未调用 OnSystemColorsChanged
所致。
我可以手动重置第二个颜色,因为我为第二个颜色属性提供 ShouldSerialize- 和 Reset- 方法,因此当系统颜色更改时,该属性的默认值也会相应更改。
那么,有什么方法可以在设计时捕获系统颜色的变化吗?
编辑:
这是一个最小化的代码示例:
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();
}
}
如果将此控件放到窗体上,此代码将执行以下操作:
默认 Color1 为 SystemColors.Highlight
默认 Color2 为较浅的颜色
如果 Color2 没有手动更改,它将自动从 Color1 派生
如果系统颜色在运行时改变,Color1和Color2都会改变
如果系统颜色在设计时改变,只有Color1会改变< /p>
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
如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。
绑定邮箱获取回复消息
由于您还没有绑定你的真实邮箱,如果其他用户或者作者回复了您的评论,将不能在第一时间通知您!
发布评论
评论(2)
如果事件在设计模式下被抑制,我不会感到太惊讶,SystemEvents 很棘手,因为它们是静态事件。通过在 Color2 的属性设置器中设置 bool 标志以指示它与默认颜色匹配来解决您的问题。设置标志时始终使用 ControlPaint.Light()。
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.
您可以订阅 SystemEvents.DisplaySettingsChanged 事件,我相信。
You can subscribe to the SystemEvents.DisplaySettingsChanged event, I believe.