WinForms controls and the red X

Most people working with WinForms have probably encountered that red X that is drawn over a control at some point and just doesn’t go away as long as the application is running. Originally, I had a look at the source of this some months ago and now, when I saw a relating question again, I thought I might document my findings here.

Note that I did that research with .NET 1 and I haven’t checked for .NET 2 yet, so in the latter case YMMV.

So where does the red X come from? Simple: The System.Windows.Forms.Control has an internal state flag for this that gets set when an exception is thrown in the control’s drawing code. So if you’ve never seen the red X but you want to, just throw a panel on a form and create a Paint event handler like this:

private void panel1_Paint(object sender, System.Windows.Forms.EventArgs e) {
  throw new Exception("Boom");

Now, the really interesting thing about the red X is that you can’t easily get rid of it once it’s popped up. The only “official” way is to restart the application. Lucky though that .NET has powerful reflection… that makes it possible to use the following method to reset the state:

void ResetExceptionState(Control control) {
  typeof(Control).InvokeMember("SetState", BindingFlags.NonPublic |
    BindingFlags.InvokeMethod | BindingFlags.Instance, null,
    control, new object[] { 0x400000, false });

So you can get that panel in the example above to have another go at drawing itself by going

panel1.Invalidate(); // invoke redraw

Of course, if the same exception is still thrown from the paint handler, there won’t be much to see as the state is immediately set back to show the X again.

Generally, of course, you should have a very close look at the reason why there’s an exception thrown in the paint handling code at all. But there are situations where you might want to control the Control’s behaviour in detail and in these cases it’s nice to be able to handle that internal state yourself.

Two additional notes:

  1. You do need certain permissions to get that reflection code to run. If you want to configure your application for exact permission sets, you should use [ReflectionPermission(SecurityAction.Demand, MemberAccess=true)] in front of the ResetExceptionState method.
  2. As I got a request for this at the time, I have a translation of the method in VB.NET, too. I don’t usually use VB, so there may be more elegant ways to do this, but here goes:
Private Sub ResetExceptionState(ByVal control As Control)
  Dim args() As [Object] = {&H400000, False}
  GetType(System.Windows.Forms.Control).InvokeMember("SetState", _
  BindingFlags.NonPublic Or BindingFlags.InvokeMethod Or _
  BindingFlags.Instance, _
  Nothing, control, args)
End Sub 

19 Comments on WinForms controls and the red X

  1. I am facing the same problem when trying to open a form that contains a datagrid froma .NET Visio Add-In.The datagrid appears with a Red X inside.If i use the same form but from a windows application the grid loads correctly.Any ideas,suggestions will be most welcome…Many Thanks


  2. Well, I think there may be not much you can do in this situation, because if the control in question is a third-party one, you might not be able to catch the exception that’s responsible for the red X to show up. I’m also not getting the distinction you make: “a form that contains a datagrid” and “using the same form from a Windows application”? What’s the difference? How were you “using” the form in the first case, where the X shows up?


  3. The control is not a third party but the usual datagrid.What i am doing is that i am creating a windows form and drag a datagrid into it.If i add this form into a windows application and execute the app the grid opens fine (with no data).When i am trying to open the form from a .NET Visio or excel Add-In i get the Red X.Below is the source code from the visio add-in.public void OnConnection(object application, Extensibility.ext_ConnectMode connectMode, object addInInst, ref System.Array custom) { applicationObject = application; addInInstance = addInInst; Form1 frm=new Form1(); frm.ShowDialog(); }In form1 i have simply added the default datagrid with no additional codeThanks in advance,Yiannis


  4. Okay, now I understand what you’re saying šŸ™‚ I thought you were doing things the other way round, that’s why I was referring to a third-party control. I’ve tried to do the same thing you’re doing, but it seems to work fine for me. I’m sorry, but I have no idea which specific circumstances might cause an exception to show up in your case.


  5. Hi,thanks for your insight to the “Red X” problem.I have situations where I get the “Red X” very often, only minutes after the application starts.I’m using 3rd-party products etc. and most of the time the Red X happens completely random and out of my code.No exception handler will catch the exceptions, just a Red X appears and so far only a reboot is a solution – which is very, very bad.So, do you know of a way to *avoid* the Red X? There should be an exception, ok, but the Red X destroys the UI and thats a bad thing.Is it possible to configure .NET to *not* draw a Red X?Any hints greatly appreciated!Walter


  6. Hi Walter – no, there’s no way to simply suppress the Red X completely. It’s .NET’s way of showing you that an error has occurred in a place where it influences the on-screen representation, and that this error wasn’t caught. The only solution to this is to find the error and fix it, or to catch the resulting exception.The question really is simple: does it (the X) appear on one of your own controls (in which case you have a bug in your drawing code) or does it appear on one of the third-party controls (in which case they have a bug in their drawing code)? You should try tracking that down, maybe also try isolating the issues by testing the controls that are used in your application in smaller test scenarios.If you are able to scale your application down to a small test and you still see the problem, and you have no idea what it might be about… if you want, I’ll have a look at it and see if I can figure anything out. But don’t send me largish stuff with lots of external references, please!


  7. Thanks for your answer. The problems are:+ the Red X appears randomly, there is no clear workflow that produces it+ it appears in 3rd party controls and/or on .NET controls+ the 3rd party says, “give me a sample”… but, no way, see 1st remarkI’m thinking of fetching the exceptions and then try to “correct” the problem with your code (“SetState”). Is there a way to check the state of a control, to see if there is a Red Xdrawn on it (“GetState”)? So I could check my controls and force a repaint on the broken ones.Thanks for your help,Walter


  8. Walter – yes, there is a method bool GetState(int flag) on the System.Windows.Forms.Control as well, so it’s possible to query the information in the same way, using Reflection. If you’re interested in that kind of thing, you should really get hold of Lutz Roeder’s Reflector here and have a look at the implementation of these details.The other thing, which maybe I shouldn’t say, is this: if you were working for me, I’d tell you to go find that problem! As you say, it happens on your own controls as well, but even if it wasn’t, the only real chance to get rid of these issues is to find an isolated test case that can reproduce them reliably. Sorry if this sounds harsh, but it’s that simple: if you haven’t found that test case yet, you haven’t looked hard enough. Just my opinion, of course.


  9. Oliver is correct, many times there is a solution to this problem by modifying your own code.It is important to track these down, because they can rear their head when the bug is reached by another route, not handled by MS code.The trick to tracking these down is to subclass the failing control, override the OnPaint method,and catch exception there — print out stack trace.This is why that works — the OnPaint method is called by the .NET framework with a special method named something like PaintWithErrorHandling, which then calls OnPaint.If you subclass, you can get stack traces of the issue, rather than the framework swallowing the whole thing.Sample call stack

    at System.Windows.Forms.CurrencyManager.get_Item(Int32 index)   at System.Windows.Forms.DataGridRow.PaintHeader(Graphics g, Rectangle visualBounds, Boolean alignToRight, Boolean rowIsDirty)   at System.Windows.Forms.DataGridRelationshipRow.PaintHeaderInside(Graphics g, Rectangle bounds, Brush backBr, Boolean alignToRight, Boolean isDirty)   at System.Windows.Forms.DataGridRelationshipRow.PaintHeader(Graphics g, Rectangle bounds, Boolean alignToRight, Boolean isDirty)   at System.Windows.Forms.DataGrid.PaintRows(Graphics g, Rectangle& boundingRect)   at System.Windows.Forms.DataGrid.PaintGrid(Graphics g, Rectangle gridBounds)   at System.Windows.Forms.DataGrid.OnPaint(PaintEventArgs pe)

    sample OnPaint

    protected override void OnPaint( Grapics g ){  try    {        base.OnPaint(g);    }    catch( Exception e )    {        System.Console.Writeline( e.StackTrace);    }}


  10. Thanks for all your suggestions.In the meantime I have implemented an application exception handlerthat fetches all unhandled exceptions, including the ones thatlead to a red cross.When this happens I try to automatically repaint all forms/controls. Thisapproach now works fine.I know this is just a workaround, but when the “Red X” occurs there is noneof my code involved… The call stack often just shows System.* – classes.Even worse, I only have to move windows across the screen and suddenly a “Red X” appears. In other situations its a 3rd party control that doesrepainting etc. Nothing I can debug or fix here.The only reason I can guess about is an old 3rd party tool we have to incorporate in our .NET Forms using the tricky and unsupported way ofusing SetParent(). This is a bad thing, I know, but it’s a *must*. And replacing that old tool with new .NET Forms will take a long time – but it will be done.Thanks,Walter


  11. Hi Walter, nice to hear you found a solution. I think that the tool you are mentioning may be a good guess for the source of your problems. Thanks for keeping us updated!


  12. Mehdy Mohajery // December 6, 2005 at 11:34 am // Reply

    Hi, I have this problem when I reject changes to dataset of a datagrid. I set the .Visible property of the datagrid to false and after changing data I set it to true back. this workaround fixed my datagrid RED X / RED Cross RegardsZMehdy Mohajery–


  13. Hi, I have being seeing a “red x” appearing in place of a datagrid, but this is very rare. I do have a custom column style, and am leaning towards its’ overriden OnPaint() method as being the culprit. The custom paint method is attempting to color the rows in the columnn based on the cell contents.Wondering if you could point out any errors in the following method? Thanks so much!

    protected override void Paint(System.Drawing.Graphics g, 	System.Drawing.Rectangle bounds, System.Windows.Forms.CurrencyManager	source, int rowNum, System.Drawing.Brush backBrush, System.Drawing.Brush 	foreBrush, bool alignToRight) {  // the idea is to conditionally set the foreBrush and/or backbrush   // depending upon some crireria on the cell value    // Here, we color anything that begins with a letter higher than 'F'   try  {     object o = this.GetColumnValueAtRow(source, rowNum);     if( o != null)     {       if( ((string)o) == "Complete" )      {        backBrush = new SolidBrush(Color.Green); 	foreBrush = new SolidBrush(Color.White);      }       else if( ((string)o) == "Error" )      {	backBrush = new SolidBrush(Color.FromArgb(255, 128, 128));      }      else      {	backBrush = new SolidBrush(Color.White);      }    }     base.Paint(g, bounds, source, rowNum, backBrush, foreBrush, alignToRight);  }   catch(Exception ex)  { /* empty catch */ }}


  14. Well, obviously your code could easily throw an exception as soon as the type of o is one that can’t be cast to a string. I would rewrite that section as

      string stringContent = o as string;  if (stringContent != null) {    if (stringContent == "Complete")       ...    else if (stringContent == "Error")       ...    else       ...  }

    Looks nicer and can’t go wrong. Now, as you’re still catching everything in the outer try/catch, I still have no idea why that routine would throw an exception. I don’t remember things as closely as I did when I wrote this post, maybe there are other interesting code paths due to the fact that you’re using an overridden method instead of an event handler? I suggest you get Reflector and find out šŸ™‚


  15. —————————Object reference not set to an instance of an object.————————— at System.Data.DataView.GetRecord(Int32 recordIndex) at System.Data.DataView.IsOriginalVersion(Int32 index) at System.Data.DataRowView.GetColumnValue(DataColumn column) at System.Data.DataColumnPropertyDescriptor.GetValue(Object component) at System.Windows.Forms.DataGridColumnStyle.GetColumnValueAtRow(CurrencyManager source, Int32 rowNum) at System.Windows.Forms.DataGridTextBoxColumn.Paint(Graphics g, Rectangle bounds, CurrencyManager source, Int32 rowNum, Brush backBrush, Brush foreBrush, Boolean alignToRight) at System.Windows.Forms.DataGridRelationshipRow.PaintCellContents(Graphics g, Rectangle cellBounds, DataGridColumnStyle column, Brush backBr, Brush foreBrush, Boolean alignToRight) at System.Windows.Forms.DataGridRow.PaintData(Graphics g, Rectangle bounds, Int32 firstVisibleColumn, Int32 columnCount, Boolean alignToRight) at System.Windows.Forms.DataGridRelationshipRow.Paint(Graphics g, Rectangle bounds, Rectangle trueRowBounds, Int32 firstVisibleColumn, Int32 numVisibleColumns, Boolean alignToRight) at System.Windows.Forms.DataGrid.PaintRows(Graphics g, Rectangle& boundingRect) at System.Windows.Forms.DataGrid.PaintGrid(Graphics g, Rectangle gridBounds) at System.Windows.Forms.DataGrid.OnPaint(PaintEventArgs pe) at System.Windows.Forms.Control.PaintWithErrorHandling(PaintEventArgs e, Int16 layer, Boolean disposeEventArgs) at System.Windows.Forms.Control.WmPaint(Message& m) at System.Windows.Forms.Control.WndProc(Message& m) at System.Windows.Forms.ControlNativeWindow.OnMessage(Message& m) at System.Windows.Forms.ControlNativeWindow.WndProc(Message& m) at System.Windows.Forms.NativeWindow.DebuggableCallback(IntPtr hWnd, Int32 msg, IntPtr wparam, IntPtr lparam) at System.Windows.Forms.UnsafeNativeMethods.DispatchMessageW(MSG& msg) at System.Windows.Forms.ComponentManager.System.Windows.Forms.UnsafeNativeMethods+IMsoComponentManager.FPushMessageLoop(Int32 dwComponentID, Int32 reason, Int32 pvLoopData) at System.Windows.Forms.ThreadContext.RunMessageLoopInner(Int32 reason, ApplicationContext context) at System.Windows.Forms.ThreadContext.RunMessageLoop(Int32 reason, ApplicationContext context) at System.Windows.Forms.Application.Run(Form mainForm) at eBuilder.Apps.TransferManagerApp.modMain.main() in C:VSSTransferManagerTransferManagerApplicationmodMain.vb:line 45—————————OK —————————dvQueue = New DataView(modMain.objClsDSTMW.dsTransferManager.transferManagerFile, "fFileStatus<>’Success’ and fFileStatus<>’Cancelled’", "fFilePriority ASC", DataViewRowState.CurrentRows) dgQueue.DataSource = dvQueuethe datagrid is bound to a dataset’s datatable and teh table is updated via another thread in the process… this causes the above exception… the thread updates the dataset at times may be 100 times a second.. so hwo do I work arround this.I tried your suggestion, but without success.thanks-smit.pelase help


  16. good.i meet the same thing as Mehdy Mohajery.but the red X doesn’t display on my computer except my pateners. and can’t catch any exception.<code> private void colConfigQuantity_BeforeCellPaint(object sender, ZTE.CCG.Common.ClientComponent.DataGrid.BeforeCellPaintEventArgs e){ DataRowView drcur = ((DataView)e.DataSource.List)[e.RowNum]; // maybe throw exception here. i will check it soon. // check the data if(drcur.Row.Table.Columns.Contains("ITEMENABLE") && (Convert.ToString(drcur["ITEMENABLE"]) == NOUSING_STR || Convert.ToString(drcur["ITEMENABLE"]) == "N")) { e.ForeBrush = mBrushConfigQuantity; }}</code>After read the post,i decide to check the code again. thanks a lot.


  17. i had this problem but
    but i solved it differently
    i hided the control before modifying it
    then after calculations happen i show the control again simply and easily solved


  18. I am also facing same problem in Custom Data Grid View. I implement below line of code and my error got resolved
    public class CustomDataGridView : DataGridView
    protected override void OnPaint(System.Windows.Forms.PaintEventArgs e)
    catch (Exception)


    • Hi Ankit,

      Thank you for your comment. At a glance, this looks pretty strange to me though – you’re catching an exception that occurs on Paint and Invalidate, thereby triggered a new Paint? If this makes the exception disappear for you, the reason must be that the painting algorithm is flaky, throwing exceptions on some iterations, but not on others.



Leave a Comment

Fill in your details below or click an icon to log in: Logo

You are commenting using your account. Log Out / Change )

Twitter picture

You are commenting using your Twitter account. Log Out / Change )

Facebook photo

You are commenting using your Facebook account. Log Out / Change )

Google+ photo

You are commenting using your Google+ account. Log Out / Change )

Connecting to %s