简体   繁体   中英

NullReferenceException in GetCachedPen function of DataGridView

We are having a NullReferenceException in the DataGridView of WinForms. Actually we are using the DataGridViewX component from DotNetBar however this is a fairly simple wrapper around the standard DataGridView so I have reason to believe it is not responsible for the issue. The stack trace is:

Unhandled thread exception System.NullReferenceException: Object reference not set to an instance of an object.
   at System.Windows.Forms.DataGridView.GetCachedPen(Color color)
   at System.Windows.Forms.DataGridView.PaintBorder(Graphics g, Rectangle clipRect, Rectangle bounds)
   at System.Windows.Forms.DataGridView.OnPaint(PaintEventArgs e)
   at DevComponents.DotNetBar.Controls.DataGridViewX.OnPaint(PaintEventArgs e)
   at System.Windows.Forms.Control.PaintWithErrorHandling(PaintEventArgs e, Int16 layer)
   at System.Windows.Forms.Control.WmPaint(Message& m)
   at System.Windows.Forms.Control.WndProc(Message& m)
   at System.Windows.Forms.DataGridView.WndProc(Message& m)
   at System.Windows.Forms.Control.ControlNativeWindow.OnMessage(Message& m)
   at System.Windows.Forms.Control.ControlNativeWindow.WndProc(Message& m)
   at System.Windows.Forms.NativeWindow.Callback(IntPtr hWnd, Int32 msg, IntPtr wparam, IntPtr lparam)

I cannot find any posts on any sites for a similar error.

I reviewed the code for this function at the .NET Reference Source , and this (internal/Friend) function takes a Color and looks inside a private hash table of cached pens:

internal Pen GetCachedPen(Color color)
{
    Pen pen = (Pen) this.pens[color];
    if (pen == null)
    {
        pen = new Pen(color);
        this.pens.Add(color, pen);
    }
    return pen;
}

https://referencesource.microsoft.com/#System.Windows.Forms/winforms/Managed/System/WinForms/DataGridViewMethods.cs,205118801a8f1ca9

The only way I can see this possibly crashing is if the Color passed in is null, however the only time I can see this function get called is:

if (paintingNeeded)
{
    if (this.BorderStyle == BorderStyle.Fixed3D)
    {
        if (Application.RenderWithVisualStyles)
        {
            Pen pen = GetCachedPen(VisualStyleInformation.TextControlBorder);
            g.DrawRectangle(pen, new Rectangle(0, 0, bounds.Width - 1, bounds.Height - 1));
        }
        else
        {
            ControlPaint.DrawBorder3D(g, bounds, Border3DStyle.Sunken);
        }
    }
    else if (this.BorderStyle == BorderStyle.FixedSingle)
    {
        Pen pen = GetCachedPen(SystemColors.ControlText);
        g.DrawRectangle(pen, new Rectangle(0, 0, bounds.Width - 1, bounds.Height - 1));
    }
    else
    {
        Debug.Fail("DataGridView.PaintBorder - Unexpected BorderStyle value.");
    }
}

The BorderStyle of the DGV is set to BorderStyle.FixedSingle, so the color parameter getting passed to GetCachedPen should be SystemColors.ControlText, which for me should never be null?

I have found some posts of seemingly "random" crashes from the DGV related to painting, but none seemed to have a solution and none were related to the GetCachedPen function. Looking at our error logging database we can see this has crashed our software 3 times in the last couple of years since we started asking our users to submit crash logs, so its certainly not something systematic we are doing wrong as this is a well used part of the software.

Has anyone seen this crash before, or something similar? Is there a solution to this? Alternatively is there some kind of workaround to these painting errors in a WinForms control?

I have the same problem. But very strange I receive it only on my laptop (Windows 10), on my workstation (Windows 7) I don't have this problem. On my laptop I receive the error consistently. A form is openend for editing, I do some editing, click on Save, then I close the form and I always receive the following error:

Unhandled Exception: System.NullReferenceException: Object reference not set to an instance of an object.
   at System.Windows.Forms.DataGridView.GetCachedPen(Color color)
   at System.Windows.Forms.DataGridView.PaintBorder(Graphics g, Rectangle clipRect, Rectangle bounds)
   at System.Windows.Forms.DataGridView.OnPaint(PaintEventArgs e)
   at System.Windows.Forms.Control.PaintWithErrorHandling(PaintEventArgs e, Int16 layer)
   at System.Windows.Forms.Control.WmPaint(Message& m)
   at System.Windows.Forms.Control.WndProc(Message& m)
   at System.Windows.Forms.DataGridView.WndProc(Message& m)
   at System.Windows.Forms.Control.ControlNativeWindow.OnMessage(Message& m)
   at System.Windows.Forms.Control.ControlNativeWindow.WndProc(Message& m)
   at System.Windows.Forms.NativeWindow.DebuggableCallback(IntPtr hWnd, Int32 msg, IntPtr wparam, IntPtr lparam)

I don't know why this is happening on only some computers but I fixed the problem as follows. The datagrid is in my case also wrapped in my own usercontrol. In the usercontrol you can override the OnPaint event.

Protected Overrides Sub OnPaint(ByVal e As System.Windows.Forms.PaintEventArgs)
    Try
        ' Dispose I will not do anything if done.
        If Not Me.IsDisposed Then
            MyBase.OnPaint(e)
        Else
            Debug.Print("SingleRecordDatagrid: Datagridview already disposed.")
        End If

    Catch ex As NullReferenceException
        ' Even if you give an exception, don't do anything.
        Debug.Print("SingleRecordDatagrid: " & ex.Message & "  StackTrace: " & vbCrLf & ex.StackTrace)
    End Try
End Sub

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM