为什么 Invalidate() 方法在设计时对我的自定义按钮不起作用?
Why doesn't Invalidate() method work for my custom button in design time?
我正在 WinForm 中处理我的自定义按钮。我已经完成工作了。但我还有最后一个问题,当 属性 被更改时,我的按钮没有 Invalidate
区域。我在 set
块和 OnResize
中调用了 Invalidate
方法,但它对按钮不起作用。但它在运行时或重建时被修复。我该如何解决?
这里是图片示例:
我的代码:
public class AltoButton : Control
{
int radius;
RoundedRectangle roundedRect;
Color inactive1, inactive2, pressed1, pressed2;
LinearGradientBrush InactiveGB, MouseOverGB, BorderGB, currentGB;
public AltoButton()
{
inactive1 = Color.FromArgb(44, 188, 210);
inactive2 = Color.FromArgb(33, 167, 188);
pressed1 = Color.FromArgb(64, 168, 183);
pressed2 = Color.FromArgb(36, 164, 183);
radius = 10;
roundedRect = new RoundedRectangle(Width, Height, radius);
SetStyle(ControlStyles.AllPaintingInWmPaint | ControlStyles.OptimizedDoubleBuffer |
ControlStyles.SupportsTransparentBackColor | ControlStyles.UserPaint, true);
}
protected override void OnPaint(PaintEventArgs e)
{
e.Graphics.SmoothingMode = SmoothingMode.HighQuality;
roundedRect = new RoundedRectangle(Width, Height, radius);
InactiveGB = new LinearGradientBrush(new Rectangle(0, 0, Width, Height), inactive1, inactive2, 90f);
MouseOverGB = new LinearGradientBrush(new Rectangle(0, 0, Width, Height), pressed1, pressed2, 90f);
BorderGB = new LinearGradientBrush(new Rectangle(0, 0, Width, Height), Color.FromArgb(162, 120, 101), Color.FromArgb(162, 120, 101), 90f);
if (currentGB == null)
currentGB = InactiveGB;
e.Graphics.FillPath(currentGB, roundedRect.Path);
e.Graphics.DrawPath(new Pen(BorderGB), roundedRect.Path);
}
protected override void OnResize(EventArgs e)
{
Invalidate();
base.OnResize(e);
}
protected override void OnMouseEnter(EventArgs e)
{
currentGB = MouseOverGB;
Invalidate();
base.OnMouseEnter(e);
}
protected override void OnMouseLeave(EventArgs e)
{
base.OnMouseLeave(e);
currentGB = InactiveGB;
Invalidate();
}
public int Radius
{
get
{
return radius;
}
set
{
radius = value;
Invalidate();
}
}
}
public class RoundedRectangle
{
Point location;
int radius;
GraphicsPath grPath;
public RoundedRectangle(int width, int height, int radius)
{
location = new Point(0, 0);
this.radius = radius;
Rectangle upperLeftRect = new Rectangle(0, 0, 2 * radius, 2 * radius);
Rectangle upperRightRect = new Rectangle(width - 2 * radius - 1, 0, 2 * radius, 2 * radius);
Rectangle lowerLeftRect = new Rectangle(0, height - 2 * radius - 1, 2 * radius, 2 * radius);
Rectangle lowerRightRect = new Rectangle(width - 2 * radius - 1, height - 2 * radius - 1, 2 * radius, 2 * radius);
grPath = new GraphicsPath();
grPath.AddArc(upperLeftRect, 180, 90);
grPath.AddArc(upperRightRect, 270, 90);
grPath.AddArc(lowerRightRect, 0, 90);
grPath.AddArc(lowerLeftRect, 90, 90);
grPath.CloseAllFigures();
}
public RoundedRectangle()
{
}
public GraphicsPath Path
{
get
{
return grPath;
}
}
public Rectangle Rect
{
get
{
return new Rectangle(location.X, location.Y, 2 * radius, 2 * radius);
}
}
}
public int Radius
{
get
{
return radius;
}
set
{
radius = value;
Invalidate();
}
}
public Color Inactive1
{
get
{
return inactive1;
}
set
{
inactive1 = value;
Invalidate();
}
}
public Color Inactive2
{
get
{
return inactive2;
}
set
{
inactive2 = value;
Invalidate();
}
}
public Color Pressed1
{
get
{
return pressed1;
}
set
{
pressed1 = value;
Invalidate();
}
}
public Color Pressed2
{
get
{
return pressed2;
}
set
{
pressed2 = value;
Invalidate();
}
}
删除 OnResize
覆盖并在您设置为 true
的样式中包含 ControlStyles.ResizeRedraw
。
或者将 Control.ResizeRedraw 属性 设置为 true
。
更新: 实际上这个问题更微不足道。您在 currentGB
字段中有一个缓存画笔,它是使用特定的 Width
和 Height
创建的。
因此您可以保持代码不变,只需将 currentGB
设置为 null
(您真的应该处理所有这些画笔,但那是另一回事)当尺寸改变时:
protected override void OnResize(EventArgs e)
{
currentGB = null;
Invalidate();
base.OnResize(e);
}
正如Ivan 上面所说,我已经使用using
语句在使用后进行处理。我已将此答案添加为补充解决方案。
protected override void OnPaint(PaintEventArgs e)
{
e.Graphics.SmoothingMode = SmoothingMode.HighQuality;
roundedRect = new RoundedRectangle(Width, Height, radius);
if (state == MouseState.Leave)
using (LinearGradientBrush inactiveGB = new LinearGradientBrush(new Rectangle(0, 0, Width, Height), inactive1, inactive2, 90f))
e.Graphics.FillPath(inactiveGB, roundedRect.Path);
else if (state == MouseState.Over)
using (LinearGradientBrush activeGB = new LinearGradientBrush(new Rectangle(0, 0, Width, Height), active1, active2, 90f))
e.Graphics.FillPath(activeGB, roundedRect.Path);
using (LinearGradientBrush BorderGB = new LinearGradientBrush(new Rectangle(0, 0, Width, Height), Color.FromArgb(162, 120, 101), Color.FromArgb(162, 120, 101), 90f))
e.Graphics.DrawPath(new Pen(BorderGB), roundedRect.Path);
}
protected override void OnResize(EventArgs e)
{
Invalidate();
base.OnResize(e);
}
protected override void OnMouseEnter(EventArgs e)
{
state = MouseState.Over;
Invalidate();
base.OnMouseEnter(e);
}
我正在 WinForm 中处理我的自定义按钮。我已经完成工作了。但我还有最后一个问题,当 属性 被更改时,我的按钮没有 Invalidate
区域。我在 set
块和 OnResize
中调用了 Invalidate
方法,但它对按钮不起作用。但它在运行时或重建时被修复。我该如何解决?
这里是图片示例:
我的代码:
public class AltoButton : Control
{
int radius;
RoundedRectangle roundedRect;
Color inactive1, inactive2, pressed1, pressed2;
LinearGradientBrush InactiveGB, MouseOverGB, BorderGB, currentGB;
public AltoButton()
{
inactive1 = Color.FromArgb(44, 188, 210);
inactive2 = Color.FromArgb(33, 167, 188);
pressed1 = Color.FromArgb(64, 168, 183);
pressed2 = Color.FromArgb(36, 164, 183);
radius = 10;
roundedRect = new RoundedRectangle(Width, Height, radius);
SetStyle(ControlStyles.AllPaintingInWmPaint | ControlStyles.OptimizedDoubleBuffer |
ControlStyles.SupportsTransparentBackColor | ControlStyles.UserPaint, true);
}
protected override void OnPaint(PaintEventArgs e)
{
e.Graphics.SmoothingMode = SmoothingMode.HighQuality;
roundedRect = new RoundedRectangle(Width, Height, radius);
InactiveGB = new LinearGradientBrush(new Rectangle(0, 0, Width, Height), inactive1, inactive2, 90f);
MouseOverGB = new LinearGradientBrush(new Rectangle(0, 0, Width, Height), pressed1, pressed2, 90f);
BorderGB = new LinearGradientBrush(new Rectangle(0, 0, Width, Height), Color.FromArgb(162, 120, 101), Color.FromArgb(162, 120, 101), 90f);
if (currentGB == null)
currentGB = InactiveGB;
e.Graphics.FillPath(currentGB, roundedRect.Path);
e.Graphics.DrawPath(new Pen(BorderGB), roundedRect.Path);
}
protected override void OnResize(EventArgs e)
{
Invalidate();
base.OnResize(e);
}
protected override void OnMouseEnter(EventArgs e)
{
currentGB = MouseOverGB;
Invalidate();
base.OnMouseEnter(e);
}
protected override void OnMouseLeave(EventArgs e)
{
base.OnMouseLeave(e);
currentGB = InactiveGB;
Invalidate();
}
public int Radius
{
get
{
return radius;
}
set
{
radius = value;
Invalidate();
}
}
}
public class RoundedRectangle
{
Point location;
int radius;
GraphicsPath grPath;
public RoundedRectangle(int width, int height, int radius)
{
location = new Point(0, 0);
this.radius = radius;
Rectangle upperLeftRect = new Rectangle(0, 0, 2 * radius, 2 * radius);
Rectangle upperRightRect = new Rectangle(width - 2 * radius - 1, 0, 2 * radius, 2 * radius);
Rectangle lowerLeftRect = new Rectangle(0, height - 2 * radius - 1, 2 * radius, 2 * radius);
Rectangle lowerRightRect = new Rectangle(width - 2 * radius - 1, height - 2 * radius - 1, 2 * radius, 2 * radius);
grPath = new GraphicsPath();
grPath.AddArc(upperLeftRect, 180, 90);
grPath.AddArc(upperRightRect, 270, 90);
grPath.AddArc(lowerRightRect, 0, 90);
grPath.AddArc(lowerLeftRect, 90, 90);
grPath.CloseAllFigures();
}
public RoundedRectangle()
{
}
public GraphicsPath Path
{
get
{
return grPath;
}
}
public Rectangle Rect
{
get
{
return new Rectangle(location.X, location.Y, 2 * radius, 2 * radius);
}
}
}
public int Radius
{
get
{
return radius;
}
set
{
radius = value;
Invalidate();
}
}
public Color Inactive1
{
get
{
return inactive1;
}
set
{
inactive1 = value;
Invalidate();
}
}
public Color Inactive2
{
get
{
return inactive2;
}
set
{
inactive2 = value;
Invalidate();
}
}
public Color Pressed1
{
get
{
return pressed1;
}
set
{
pressed1 = value;
Invalidate();
}
}
public Color Pressed2
{
get
{
return pressed2;
}
set
{
pressed2 = value;
Invalidate();
}
}
删除 OnResize
覆盖并在您设置为 true
的样式中包含 ControlStyles.ResizeRedraw
。
或者将 Control.ResizeRedraw 属性 设置为 true
。
更新: 实际上这个问题更微不足道。您在 currentGB
字段中有一个缓存画笔,它是使用特定的 Width
和 Height
创建的。
因此您可以保持代码不变,只需将 currentGB
设置为 null
(您真的应该处理所有这些画笔,但那是另一回事)当尺寸改变时:
protected override void OnResize(EventArgs e)
{
currentGB = null;
Invalidate();
base.OnResize(e);
}
正如Ivan 上面所说,我已经使用using
语句在使用后进行处理。我已将此答案添加为补充解决方案。
protected override void OnPaint(PaintEventArgs e)
{
e.Graphics.SmoothingMode = SmoothingMode.HighQuality;
roundedRect = new RoundedRectangle(Width, Height, radius);
if (state == MouseState.Leave)
using (LinearGradientBrush inactiveGB = new LinearGradientBrush(new Rectangle(0, 0, Width, Height), inactive1, inactive2, 90f))
e.Graphics.FillPath(inactiveGB, roundedRect.Path);
else if (state == MouseState.Over)
using (LinearGradientBrush activeGB = new LinearGradientBrush(new Rectangle(0, 0, Width, Height), active1, active2, 90f))
e.Graphics.FillPath(activeGB, roundedRect.Path);
using (LinearGradientBrush BorderGB = new LinearGradientBrush(new Rectangle(0, 0, Width, Height), Color.FromArgb(162, 120, 101), Color.FromArgb(162, 120, 101), 90f))
e.Graphics.DrawPath(new Pen(BorderGB), roundedRect.Path);
}
protected override void OnResize(EventArgs e)
{
Invalidate();
base.OnResize(e);
}
protected override void OnMouseEnter(EventArgs e)
{
state = MouseState.Over;
Invalidate();
base.OnMouseEnter(e);
}