You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

拖拽自定义ProgressBar到Form1设计器时参数无效异常排查

自定义ProgressBar拖拽设计器触发异常问题

首次把自定义ProgressBar从工具箱拖到Form1设计器时能正常运行,但现在每次拖拽都会触发异常,而且完全没改过代码。

异常触发点

异常发生在DrawStringIfNeeded方法的第165行:g.DrawString(text, TextFont, _textColourBrush, location);,错误提示为参数无效。

问题根源

  1. Font对象异常:TextFont属性的默认Font对象在设计器反复序列化、控件销毁重建的过程中,可能被意外释放,导致绘制时引用无效对象。
  2. 画笔对象提前释放:TextColor和ProgressColor的setter中直接Dispose旧画笔,但设计器环境下可能多次调用该方法,或者在控件未完全初始化时就触发绘制,导致画笔已处于释放状态。
  3. 设计器模式下无特殊处理:控件在设计器中绘制时,没有区分运行时和设计时逻辑,复杂的绘制操作容易触发环境兼容性问题。

修复方案

1. 重构TextFont属性,避免无效引用

把自动属性改成带字段的属性,增加空值检查和资源释放逻辑,防止Font对象失效:

private Font _textFont;
[Description("进度条上文本的字体"), Category("附加选项")]
public Font TextFont
{
    get => _textFont ?? (_textFont = new Font(FontFamily.GenericSerif, 14, FontStyle.Bold | FontStyle.Italic));
    set
    {
        if (_textFont != value)
        {
            // 仅释放非默认的自定义字体
            if (_textFont != null && !_textFont.Equals(new Font(FontFamily.GenericSerif, 14, FontStyle.Bold | FontStyle.Italic)))
            {
                _textFont.Dispose();
            }
            _textFont = value;
            Invalidate();
        }
    }
}

2. 修正画笔初始化逻辑,避免共享系统画笔

不要直接使用Brushes.Black这类系统共享画笔,改为创建独立的SolidBrush实例,防止系统画笔被意外释放:

private SolidBrush _textColourBrush = new SolidBrush(Color.Black);
[Category("附加选项")]
public Color TextColor
{
    get => _textColourBrush.Color;
    set
    {
        if (_textColourBrush.Color != value)
        {
            _textColourBrush.Dispose();
            _textColourBrush = new SolidBrush(value);
            Invalidate();
        }
    }
}

private SolidBrush _progressColourBrush = new SolidBrush(Color.LightGreen);
[Category("附加选项"), Browsable(true), EditorBrowsable(EditorBrowsableState.Always)]
public Color ProgressColor
{
    get => _progressColourBrush.Color;
    set
    {
        if (_progressColourBrush.Color != value)
        {
            _progressColourBrush.Dispose();
            _progressColourBrush = new SolidBrush(value);
            Invalidate();
        }
    }
}

3. 绘制前增加有效性检查,捕获异常

在DrawStringIfNeeded方法中,提前检查Font、画笔的有效性,捕获参数异常避免设计器崩溃:

private void DrawStringIfNeeded(Graphics g)
{
    if (VisualMode == ProgressBarDisplayMode.NoText || TextFont == null || _textColourBrush == null)
    {
        return;
    }

    string text = _textToDraw;
    if (string.IsNullOrEmpty(text))
    {
        return;
    }

    try
    {
        SizeF len = g.MeasureString(text, TextFont);
        Point location = new Point((Width / 2) - (int)len.Width / 2, (Height / 2) - (int)len.Height / 2);
        g.DrawString(text, TextFont, _textColourBrush, location);
    }
    catch (ArgumentException)
    {
        // 捕获参数无效异常,触发重绘
        Invalidate();
    }
}

4. 区分设计器与运行时绘制逻辑

在OnPaint方法中判断是否处于设计器模式,设计器下使用基础绘制逻辑,避免复杂操作触发异常:

protected override void OnPaint(PaintEventArgs e)
{
    if (e.Graphics == null)
    {
        return;
    }

    // 设计器模式下用默认绘制逻辑
    if (DesignMode)
    {
        base.OnPaint(e);
        return;
    }

    Graphics g = e.Graphics;
    DrawProgressBar(g);
    DrawStringIfNeeded(g);
}

内容的提问来源于stack exchange,提问作者Daniel Lip

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.06.20 13:04:53