Winforms OnPaint在图表中的异常后没有被调用

时间:2018-01-09 21:59:27

标签: c# winforms charts paint onpaint

你好互联网的开发者!

如果轴或显示的点采用它们不应具有的值,则Winforms.DataVisualization.Charting.Chart将自身绘制为一个大红叉。

当OnPaint方法内发生异常时会发生这种情况。本主题的其他问题建议创建一个子类并重写OnPaint。这就是我所做的,这就是我如何找出导致问题的原因。

有趣的问题是:如何摆脱这种错误状态? 我尝试将属性设置为有效值并清除所有内容,调用Invalidate()和常用的东西。发生错误后再也不会再调用OnPaint方法。

winforms中是否存在导致这种情况的某种行为?可以将控件标记为“失败超出恢复”吗? 当我将控件移动到失败状态图表上方时,红色x被重绘,因此它被绘制,但不是自己绘制。

我想知道我在这里缺少哪种细节知识。

PS:SetStyle没有帮助,在错误发生之前调用OnPaint并且无法解决它。

附录A:重新编译 我反汇编了整个Winforms.DataVisualization.Charting程序集的源代码并重新编译它。通过评论抛出;在图表OnPaint中,有一个方法不会留下一个预期但只是绘制一个“错误已经发生”-image本身。 在这种情况下,重新绘制不会永远禁用。

不知何故,如果Winforms抛出异常,它就会从绘图顺序中删除控件。

1 个答案:

答案 0 :(得分:0)

调试提取的程序集源代码版本可以深入了解该问题。首先,根据提供的@TnTinMn链接,在抛出异常后永远从OnPaint中排除的控件是正常行为。

然而,图表本身在OnPaint中有一个代码路径,它不会重置用于在OnPaint运行时阻止失效的内部字段。

以下代码是图表的子类,它捕获OnPaint异常并使用反射来重置私有字段。因此,如果图表遇到错误状态,可以通过设置有效值并重新绘制来重置它。

创建图表控件后,请确保设置轴的最小和最大属性,甚至是未使用的属性。属性setter不仅仅是将值放入字段中。对我来说,没有帮助没有抛出异常。

/// <summary>
/// Subclass catches exception thrown from base.OnPaint and thus prevents the red x.
/// Resets base classes private field "disableInvalidates" via reflection to reallow invalidation.
/// </summary>
public class ChartSubclass : Chart
{
    private readonly System.Reflection.FieldInfo disableInvalidatesField;

    public ChartSubclass()
    {
        this.disableInvalidatesField = typeof(Chart).GetField("disableInvalidates",
            System.Reflection.BindingFlags.NonPublic |
            System.Reflection.BindingFlags.Public |
            System.Reflection.BindingFlags.Static |
            System.Reflection.BindingFlags.SetField |
            System.Reflection.BindingFlags.Instance);
    }

    protected override void OnPaint(PaintEventArgs e)
    {
        try
        {
            base.OnPaint(e);
        }
        catch (Exception ex)
        {
            this.disableInvalidatesField.SetValue(this, false);
            this.DrawErrorState(e, ex);
        }
    }

    /// <summary>
    /// Draws error message.
    /// </summary>
    private void DrawErrorState(PaintEventArgs e, Exception ex)
    {
        var graphics = e.Graphics;
        graphics.FillRectangle(Brushes.White, 0, 0, base.Width, base.Height);
        var layoutRectangle = new RectangleF(3f, 3f, base.Width - 6, base.Height - 6);
        using (var stringFormat = new StringFormat())
        {
            stringFormat.Alignment = StringAlignment.Center;
            stringFormat.LineAlignment = StringAlignment.Center;
            graphics.DrawString(ex.Message, this.Font, Brushes.Black, layoutRectangle, stringFormat);
        }
    }
}