【问题标题】:Why doesn't Invalidate() method work for my custom button in design time?为什么 Invalidate() 方法在设计时对我的自定义按钮不起作用?
【发布时间】:2016-03-20 23:29:26
【问题描述】:

我正在处理 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();
            }
        }

【问题讨论】:

  • 您的 currentGB 字段被窃听。它指的是旧画笔,而不是您创建的具有正确大小的新画笔。只是不要存放画笔,它们的制作成本非常低,但保存起来却非常昂贵。您现在还可以正确使用 using 语句。

标签: c# winforms button custom-controls invalidation


【解决方案1】:

删除OnResize 覆盖并将ControlStyles.ResizeRedraw 包含在您设置为true 的样式中。

或者将Control.ResizeRedraw属性设置为true

更新:其实这个问题更小。您在currentGB 字段中有一个缓存画笔,它是使用特定的WidthHeight 创建的。

所以你可以保持你的代码原样,当大小改变时,只需将currentGB 设置为null(你真的应该处理所有这些画笔,但这是另一回事):

protected override void OnResize(EventArgs e)
{
    currentGB = null;
    Invalidate();
    base.OnResize(e);
}

【讨论】:

  • 感谢@Ivan,效果很好。实际上,我正在存储可浏览属性(get-set)的画笔,例如颜色。如果画笔在使用后被丢弃,如何获取当前的设计师属性值?我之前没有添加的剩余代码在上面的更新问题中。也许有更有效的方法。请看一下。
  • 好吧,我照你说的做了。没有存储任何东西。只是使用了鼠标状态和 if-else 条件。再次感谢@Ivan。你很棒。
【解决方案2】:

正如 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);
        }

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2019-12-11
    • 2019-08-03
    • 1970-01-01
    • 1970-01-01
    • 2021-07-13
    相关资源
    最近更新 更多