为什么 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 字段中有一个缓存画笔,它是使用特定的 WidthHeight 创建的。

因此您可以保持代码不变,只需将 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);
        }