Debugging Puzzler - WinForms crash - Can you figure out what caused it?

Earlier this week I was doing a presentation and since the company I presented for had mostly winforms developers I wanted to convert all my ASP.NET debugging demos to winforms equivalents for the presentation.

As I was converting my first demo (a performance issue) I ran into a bit of a snag because the first time I ran the demo (which populates 4 datagridviews with product information) things worked fine. I clicked the Featured Products button, my datagrids were nicely filled, I could reproduce my performance issue and debug it.

The second time I clicked the button to reproduce the issue however I was met with this:

WinformsCrash 

Instead of data in my datagrids they were just covered with big red X:es and the application crashed with a NullReferenceException (Object reference not set to an instance of an object) in System.Windows.Forms.DataGridViewRowHeaderCell.PaintPrivate.

I have attached the faulting application to this post if you want to try reproducing and debugging the issue and figure out what happened...  feel free to post your suggestions for causes and resolutions in the comments...

The first comment that leads to a resolution will be dubbed "Master Debugger August 2008":)  I'll post my answer later on ...

Have fun,

Tess

DebuggingPuzzler1.exe

Comments

  • Anonymous
    August 27, 2008
    I bet that you load those DataGridViews from a different thread than the UI thread without using Control.Invoke/BeginInvoke :)

  • Anonymous
    August 27, 2008
    The comment has been removed

  • Anonymous
    August 27, 2008
    Tess...It works perfectly on my Vista dev system. (VS2008 Pro with most recent updates.) I created a Video so you can see: http://iis7test.com/debug/debug001.aspx Odd?

  • Anonymous
    August 27, 2008
    I guess the probability of exception depends on the duration of sleep call ...

  • Anonymous
    August 27, 2008
    Wisemx,  in the video you only clicked the Featured Products link once, try clicking it again... btw it's a bit of a timing issue

  • Anonymous
    August 27, 2008
    Man thats funny... this is caused by threading issues? I haven't done winform programming since 2003~, back when I was (well, like almost everyone) much less knowledgeable about .NET (though I guess this particular issue is true for most windows app development). There I was,  in my newbie self and got that particular issue. Never was able to fix it, and eventually moved to asp.net development, so I never hit it again, nor thought twice about it. Only took 5 years, but now I know what caused it :)

  • Anonymous
    August 27, 2008
    Looks like you're setting the DataGridView.DataSource on a background thread in FillFeaturedProducts.  Almost every .NET control does not support setting control data on any other thread than the main GUI thread.  Not to mention, DataGridView is documented as "Any instance members are not guaranteed to be thread safe." I would suggest marshaling setting DataGridView.DataSource back to the GUI thread. (InvokeRequired/BeginInvoke is one way of doing that).

  • Anonymous
    August 27, 2008
    I did have a look with Windbg and the exception stacks. But I cheated and had also a look with reflector ;-). There are 4 theads spawned which do bind their data from a slow method. The first time it works since there was no data yet there. But the second time the returned DataView    ((DataGridView) grid).DataSource = view; will cause  a window event OnDataSourceChanged. Because that event comes from a different thread it messes the window message loop up which was perhaps already processing some redrawing. In effect one thread alters the data of another thread while he tries to access it. That results in NullReferenceExceptions. One solution would be to call the    ((DataGridView) grid).DataSource = view; from the man UI thread via   Action d = () => {    ((DataGridView) grid).DataSource = view;   }   base.Invoke( d ); That should do the trick. Yours,  Alois Kraus

  • Anonymous
    August 27, 2008
    If you run the application in debug mode it will tell you what is wrong (Cross-thread operation not valid: Control 'dgFeaturedEMEA' accessed from a thread other than the thread it was created on.) The solution is an old fashion invoke if invoke is required. public void FillFeaturedProducts(object grid) {    DataView view = new DataView(dl.GetFeaturedProducts());    this.SetDataSource((DataGridView)grid, view); } private delegate void SetDataSourceDelegate(DataGridView grid, DataView view); public void SetDataSource(DataGridView grid, DataView view) {    if (this.InvokeRequired)    {        this.BeginInvoke(new SetDataSourceDelegate(SetDataSource), grid, view);        return;    }    grid.DataSource = view; }

  • Anonymous
    August 27, 2008
    The comment has been removed

  • Anonymous
    August 27, 2008
    just ran it under MSVS debugger, and got an exception: Cross-thread operation not valid: Control 'dgFeaturedEMEA' accessed from a thread other than the thread it was created on. this seems to explain everything %)

  • Anonymous
    August 27, 2008
    Link Listing - August 27, 2008

  • Anonymous
    August 27, 2008
    WPF Filtering a list of items with the PropertyFilterGroupView control [Via: Josh Smith ] Code Camps...

  • Anonymous
    August 27, 2008
    i wonder if the thread that is supposed to populate the datagrid is trying to make use of a brush destroyed by the GUI thread (before redraw or something). I don't remember reading anything about that big red X, not even from the Datagridview team ...

  • Anonymous
    August 27, 2008
    Nice debugging everyone:) Actually Mike will be "Master Debugger August 2008" since he took it in the very first comment, which was about 5 minutes after I made the post:)  A bit discouraging I might add, I thought it would take a little longer for someone to figure it out:) The problem, as Mike (and others) stated, is that I am performing operations on a winforms control from a non-ui thread, which leads to issues like this one since operations on winforms controls are not thread-safe The solution, which he also mentioned is to use Control.Invoke/BeginInvoke as described in this article http://msdn.microsoft.com/en-us/library/ms171728(VS.80).aspx So... it all comes down to me not knowing how things work in a winforms environment:)

  • Anonymous
    August 28, 2008
    Debugging it under Visual Studio flags these errors right away: "Cross-thread operation not valid: Control 'dgFeaturedAmericas' accessed from a thread other than the thread it was created on."

  • Anonymous
    May 06, 2010
    The reply by Patrik is really awesome. Saved me many hours of work. Patrik the example you gave made it so simple for me. Really you should have separate tutorial on the use of Control.Invoke and Control.InvokeRequired on net.