【问题标题】:Overriding OnPaintBackground makes the Designer view misbehave覆盖 OnPaintBackground 会使设计器视图行为异常
【发布时间】:2013-06-19 07:31:23
【问题描述】:

我必须在我的TableLayoutPanel 上禁用OnPaintBackground 以消除首先绘制的背景引起的闪烁(因为我正在使用paint 方法在TLP 上绘图,是的,我需要一个TLP,因为它包含许多控件出于某种目的)。所以我的代码如下:

    public static bool FlickerPanel = false;
    public class FlickerTableLayoutPanel : TableLayoutPanel
    {
        protected override void OnPaintBackground(PaintEventArgs e)
        {
            if (FlickerPanel)
                base.OnPaintBackground(e);
        }
    }

然后在我的绘画方法中,我让它绘制它自己的背景。所以在运行时它很好。

编辑:我发现了问题的根源。通过覆盖 OnPaintBackground,它会禁用任何让设计者绘制背景的代码。如果我将覆盖全部删除,则不会出现图形故障。

        protected override void OnPaintBackground(PaintEventArgs e)
        {
                base.OnPaintBackground(e);
        }

即使上面的代码也禁用了设计视图渲染并导致图形故障。非常感谢任何帮助!

【问题讨论】:

  • 您不能只跳过 OnPaintBackground,这就是 TLP 自己绘制的地方。在基本调用之后将所需的 e.Graphics 方法调用添加到该方法。如果这仍然太明显,那么添加一个构造函数并将 DoubleBuffered 属性设置为 true。
  • 经过一番研究,我认为 Hans Passant 建议的 DoubleBuffered 属性可以解决问题。
  • @HansPassant 太棒了! DoubleBuffered 属性确实有效。所以我输入了public TLP(){ base.DoubleBuffered = true; },它成功了!这与覆盖默认构造函数是一样的吗?我应该在原始默认构造函数中添加什么内容吗?

标签: c# winforms


【解决方案1】:

我在检测我的表单是否处于设计模式时也遇到了问题。我解决了如下:

首先,我必须编写一个IsDesignMode() 方法:

public static bool IsDesignMode(Control control)
{
    if (LicenseManager.UsageMode == LicenseUsageMode.Designtime)  // Initial quick check.
    {
        return true;
    }

    while (control != null)
    {
        System.ComponentModel.ISite site = control.Site;

        if ((site != null) && (site.DesignMode))
            return true;

        control = control.Parent;
    }

    return false;
}

我将该方法放在共享库程序集中(下例中的命名空间“Windows.Forms.Utilities”),因为我在很多项目中都使用它。

然后对于我需要知道它是否处于设计模式的每个用户或自定义控件,我必须添加一个private bool _isDesignMode 字段并覆盖OnHandleCreated(),如下所示:

protected override void OnHandleCreated(EventArgs e)
{
    base.OnHandleCreated(e);
    _isDesignMode = Windows.Forms.Utilities.IsDesignMode(this);
}

然后我可以在任何需要的地方使用_isDesignMode

【讨论】:

  • 不错的代码,肯定会把它添加到武器库中。可悲的是,我发现即使我将if 全部删除也会出现问题。仅通过覆盖 OnPaintBackground 甚至将其传递给原始基础,它仍然会产生相同的图形故障。
  • 据我所知,每个控件都有一个名为 DesignMode 的受保护属性,为什么不直接使用它呢?
  • @KingKing 因为它并不总是适用于嵌套控件。 See here for example
  • @MatthewWatson 谢谢,我能理解你的代码,如果你说的是真的,如果没有任何经验,这似乎不容易知道
  • 即使我继续使用基本原件,为什么只是覆盖 BackgroundPaint 会禁用设计器代码来显示它?我可以将 BackGroundPaint 设计器代码添加到我的重写方法吗?
【解决方案2】:

您可以使用 if 语句将 OnPaintBackground 方法中的代码括起来,以检测您在设计时是否像这样:

if (System.ComponentModel.LicenseManager.UsageMode ==
System.ComponentModel.LicenseUsageMode.Designtime)

【讨论】:

  • 这是很酷的代码。可悲的是,在尝试了这段精彩的代码后,我发现无论如何都会发生这种行为。
  • @CodeCamper 这可能是因为该测试并不总是适用于嵌套控件。
  • @MatthewWatson 但我将if 检查全部删除,然后像我在问题底部所做的那样运行基类,但它仍然无法正常工作。我什至不知道从哪里开始解决这个问题,因为我以前从未为设计师编写过代码。
【解决方案3】:

我只是想对@matthew-watson 提供的解决方案进行轻微升级。作为一种扩展方法,语法变得更易读。

public static partial class ExtensionMethods
{
    public static bool IsInDesignMode(this Control source)
    {
        var result = LicenseManager.UsageMode == LicenseUsageMode.Designtime;

        while (result == false && source != null)
        {
            result = source.Site != null && source.Site.DesignMode;

            source = source.Parent;
        }

        return result;
    }
}

并像这样使用

protected override void OnPaintBackground(PaintEventArgs pevent)
{
    if (this.IsInDesignMode())
    {
        base.OnPaintBackground(pevent);
    }
}

【讨论】:

    【解决方案4】:

    什么也不做 onPaintBackground() 函数。它可以防止背景图像被绘制并且应该修复闪烁。

    protected override void OnPaintBackground(PaintEventArgs e)
    {
    }
    

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 2018-04-04
      • 2012-03-15
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2011-12-25
      • 1970-01-01
      相关资源
      最近更新 更多