你好互联网的开发者!
如果轴或显示的点采用它们不应具有的值,则Winforms.DataVisualization.Charting.Chart将自身绘制为一个大红叉。
当OnPaint方法内发生异常时会发生这种情况。本主题的其他问题建议创建一个子类并重写OnPaint。这就是我所做的,这就是我如何找出导致问题的原因。
有趣的问题是:如何摆脱这种错误状态? 我尝试将属性设置为有效值并清除所有内容,调用Invalidate()和常用的东西。发生错误后再也不会再调用OnPaint方法。
winforms中是否存在导致这种情况的某种行为?可以将控件标记为“失败超出恢复”吗? 当我将控件移动到失败状态图表上方时,红色x被重绘,因此它被绘制,但不是自己绘制。
我想知道我在这里缺少哪种细节知识。
PS:SetStyle没有帮助,在错误发生之前调用OnPaint并且无法解决它。
附录A:重新编译 我反汇编了整个Winforms.DataVisualization.Charting程序集的源代码并重新编译它。通过评论抛出;在图表OnPaint中,有一个方法不会留下一个预期但只是绘制一个“错误已经发生”-image本身。 在这种情况下,重新绘制不会永远禁用。
不知何故,如果Winforms抛出异常,它就会从绘图顺序中删除控件。
答案 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);
}
}
}