How to handle nullreference exception in "NM_CUSTOMDRAW" notification message?

Rashmi Gupta 81 Reputation points
2022-06-28T12:23:02.77+00:00

Hello,
I have a windows forms application having a user control . The user control has a Treeview named as TriView. TriView's drawmode is set to OwnerDrawAll.
The form is visible all the time. When I run my application and switch between the other controls and TriView 3-4-5 times, I get a NullReferenceEXception while populating TriView

   TriView.Nodes.Add(oTreeNode)  

None of the fields are null here. Still I get the exception.

These are the details of exception:

System.NullReferenceException: Object reference not set to an instance of an object.
at System.Windows.Forms.TreeNode.get_Handle()
at System.Windows.Forms.TreeNode.get_RowBounds()
at System.Windows.Forms.TreeView.CustomDraw(Message& m)
at System.Windows.Forms.TreeView.WmNotify(Message& m)
at System.Windows.Forms.TreeView.WndProc(Message& m)
at System.Windows.Forms.NativeWindow.Callback(IntPtr hWnd, Int32 msg, IntPtr wparam, IntPtr lparam)

Similar question is asked here: nullreference-exception-in-treenode-get-handle-in-ownerdrawn-treeview

Author says she has solved the issue by handling the null reference exception in "NM_CUSTOMDRAW" notification message but didn't tell how she did it. I neither get any source for the same through google search. I don't know how to handle messages.

Can any one help me by showing some code to handle the null reference exception in "NM_CUSTOMDRAW" notification message.

Windows Forms
Windows Forms
A set of .NET Framework managed libraries for developing graphical user interfaces.
1,909 questions
.NET
.NET
Microsoft Technologies based on the .NET software framework.
3,985 questions
C#
C#
An object-oriented and type-safe programming language that has its roots in the C family of languages and includes support for component-oriented programming.
11,121 questions
VB
VB
An object-oriented programming language developed by Microsoft that is implemented on the .NET Framework. Previously known as Visual Basic .NET.
2,756 questions
.NET Runtime
.NET Runtime
.NET: Microsoft Technologies based on the .NET software framework.Runtime: An environment required to run apps that aren't compiled to machine language.
1,179 questions
0 comments No comments
{count} votes

Accepted answer
  1. Castorix31 86,316 Reputation points
    2022-06-28T18:21:11.447+00:00

    NM_CUSTOMDRAW is handled in WM_NOFITY

    If your TreeView control is inherited from standard TreeView, use WM_REFLECT + WM_NOFITY
    Something like this =>

    public class TreeViewCustom : TreeView  
    {  
        private const int NM_FIRST = 0;  
        private const int NM_CLICK = NM_FIRST - 2;  
        private const int NM_CUSTOMDRAW = NM_FIRST - 12;  
        private const int WM_REFLECT = 0x2000;  
        private const int WM_NOFITY = 0x004E;  
    
        [StructLayout(LayoutKind.Sequential)]  
        private struct NMHDR  
        {  
            public IntPtr hwndFrom;  
            public IntPtr idFrom;  
            public int code;  
        }  
    
        [StructLayout(LayoutKind.Sequential)]  
        private struct NMCUSTOMDRAW  
        {  
            public NMHDR hdr;  
            public int dwDrawStage;  
            public IntPtr hdc;  
            public RECT rc;  
            public IntPtr dwItemSpec;  
            public uint uItemState;  
            public IntPtr lItemlParam;  
        }  
    
        [StructLayout(LayoutKind.Sequential)]  
        private class NMTVCUSTOMDRAW  
        {  
            public NMCUSTOMDRAW nmcd;  
            public int clrText;  
            public int clrTextBk;  
            public int iLevel;  
        }  
    
        [FlagsAttribute]  
        internal enum CDRF  
        {  
            CDRF_DODEFAULT = 0x00000000,  
            CDRF_NEWFONT = 0x00000002,  
            CDRF_SKIPDEFAULT = 0x00000004,  
            CDRF_DOERASE = 0x00000008,  
            CDRF_SKIPPOSTPAINT = 0x00000100,  
            CDRF_NOTIFYPOSTPAINT = 0x00000010,  
            CDRF_NOTIFYITEMDRAW = 0x00000020,  
            CDRF_NOTIFYSUBITEMDRAW = 0x00000020,  
            CDRF_NOTIFYPOSTERASE = 0x00000040  
        }  
    
        [FlagsAttribute]  
        internal enum CDDS  
        {  
            CDDS_PREPAINT = 0x00000001,  
            CDDS_POSTPAINT = 0x00000002,  
            CDDS_PREERASE = 0x00000003,  
            CDDS_POSTERASE = 0x00000004,  
            CDDS_ITEM = 0x00010000,  
            CDDS_ITEMPREPAINT = (CDDS_ITEM | CDDS_PREPAINT),  
            CDDS_ITEMPOSTPAINT = (CDDS_ITEM | CDDS_POSTPAINT),  
            CDDS_ITEMPREERASE = (CDDS_ITEM | CDDS_PREERASE),  
            CDDS_ITEMPOSTERASE = (CDDS_ITEM | CDDS_POSTERASE),  
            CDDS_SUBITEM = 0x00020000  
        }  
    
        [StructLayout(LayoutKind.Sequential)]  
        public struct RECT  
        {  
            public int left;  
            public int top;  
            public int right;  
            public int bottom;  
        }  
    
        public TreeViewCustom()  
        {  
            DrawMode = TreeViewDrawMode.OwnerDrawAll;  
            // Code...  
        }  
    
        protected override void WndProc(ref Message m)  
        {  
            if (m.Msg == WM_REFLECT + WM_NOFITY)  
            {  
                var pnmhdr = (NMHDR)m.GetLParam(typeof(NMHDR));  
                if (pnmhdr.code == NM_CUSTOMDRAW)  
                {  
                    try  
                    {  
                    		// Test code...  
                        var pnmtv = (NMTVCUSTOMDRAW)m.GetLParam(typeof(NMTVCUSTOMDRAW));  
                        switch (pnmtv.nmcd.dwDrawStage)  
                        {  
                            case (int)CDDS.CDDS_PREPAINT:  
                                {  
                                    m.Result = new IntPtr((int)CDRF.CDRF_NOTIFYITEMDRAW);  
                                }  
                                break;  
                            case (int)CDDS.CDDS_ITEMPREPAINT:  
                                {  
                                    pnmtv.clrText = ColorTranslator.ToWin32(System.Drawing.Color.Red);  
                                    //pnmtv.clrTextBk = ColorTranslator.ToWin32(System.Drawing.Color.Lime);  
                                    Marshal.StructureToPtr(pnmtv, m.LParam, false);  
                                    m.Result = new IntPtr((int)(CDRF.CDRF_NEWFONT | CDRF.CDRF_NOTIFYPOSTPAINT));  
                                }  
                                break;  
                            case (int)CDDS.CDDS_ITEMPOSTPAINT:  
                                {  
                                    // Code...  
                                }  
                                break;  
                        }  
    
                    }  
                    catch (NullReferenceException)  
                    {  
                        // Code...  
                    }                      
                }  
                return;  
            }             
            else  
                base.WndProc(ref m);  
        }  
    }  
    
    2 people found this answer helpful.

0 additional answers

Sort by: Most helpful

Your answer

Answers can be marked as Accepted Answers by the question author, which helps users to know the answer solved the author's problem.