none
Custom DataGridView Forms Designer Auto-Generating Columns Problem RRS feed

  • Question

  • Greetings All,

    I've had no luck finding any reference to this problem so I thought I'd try submitting to your collective wisdom.

    To whit:
    I've got a C# class in a custom forms control library that inherits (indirectly) from DataGridView. This custom DataGridView is designed to allow for editing of a specific type of business object with a number of complex relationships (i.e., to show ComboBoxes displaying the Name property of objects related via bridge tables and the like). Since it's purpose is fairly constrained, I used the VS2008 designer to explicitly specify the columns and set AutoGenerateColumns = false (sure wish I knew why this property is only available at runtime).

    All works fine, until I open the designer for the containing WinForm. At that point, the IDE seems to auto-generate copies of all of the (already-specified) columns in the custom DataGridView. Since some of the original columns (the DataGridViewComboBoxColumns, usually) require run-time data binding of options, the app blows up upon binding the grid with "Invalid Combo Box value" errors and the like (since the copies of the combo box columns have no items populated).

    I can fix this, temporarily, by manually editing the form's <form name>.designer.cs file, but, as soon as I re-open the form's designer, all my hand-editing is overwritten and I'm back where I began.

    Does anyone know how to suppress the auto-generation of columns by the form's designer?

    Thanks in advance...
    • Moved by CoolDadTx Friday, October 12, 2012 2:51 PM Winforms related (From:Visual C# IDE)
    Thursday, January 15, 2009 10:05 PM

All replies

  • Are you setting AutoGenerateColumns to false in the constructor for your derived class?  The problem with this approach is that nothing prevents someone from resetting it.  An alternative might be to react to the OnDataSourceChanged/OnDataMemberChanged event and always reset the property to false to ensure it doesn't get set programmatically.  I believe this is still early enough in the process that the grid hasn't regenerated the columns yet.

    An alternative, although I'm hesitant, is to redefine AutoGenerateColumns with the new modifier and ignore set requests.  More importantly always return false from the getter.

    Michael Taylor - 1/16/09
    http://p3net.mvps.org
    Friday, January 16, 2009 2:58 PM
  • Michael,

    Many thanks. I re-defined the AutoGenerateColumns property to swallow any attempt to set the property and the designer ceased to fill the designer.cs file with duplicate columns!

    The strange thing is, the custom DGV is only bound to its DataSource (a typed List of objects) at run time - no BindingSources or the like are used at all. Somehow, the designer for the hosting form, upon opening the form, was iterating through the custom DGV's pre-defined columns and creating renamed (i.e., dataGridViewTextBoxColumn142) versions of every one of them. Since this happened every time I opened the form in design view, and since the custom DGV has a large number of columns to begin with, things got out of hand very quickly. I can only wonder why the designer would try so aggressively to infer the bound properties of an assumed DataSource - probably related to the reason that AutoGenerateColumns is only available programmatically....

    Thanks again.

    Ian Russell
    Tuesday, January 20, 2009 9:43 PM
  • Correction: Redefining AutoGenerateColumns didn't work. On about the fourth opening of the form in design view, the designer once again started churning out duplicate columns (I've got a useful collection of regular expressions for cleaning up the <form>.designer.cs file, should anyone else be suffering the same fate).

    I've since added

    this.AutoGenerateColumns = false;


    to the OnDataSourceChanged/OnDataMemberChanged event handlers. No duplicate columns yet...
    Wednesday, January 21, 2009 2:19 PM
  • OK, adding
    this
    .AutoGenerateColumns = false;
    to the OnDataSourceChanged/OnDataMemberChanged event handlers doesn't work, either - I'm back to clearing out auto-generated columns from the designer.cs file manually (feels like bailing out the bilge of a leaky ship).

    As far as I can tell, the designer ignores the AutoGenerateColumns property. I even tried
    protected override DataGridViewColumnCollection CreateColumnsInstance()
    {
        if (!(this.DesignMode && this.FindForm() != null))
            return base.CreateColumnsInstance();
        else
            return null;
    }

    and 

    void SubjectGrid_ColumnAdded(object sender, DataGridViewColumnEventArgs e)
    {
        if (this.DesignMode && this.FindForm() != null)
            throw new NotImplementedException();
    }
    ...no dice - neither of these seem to be called in design mode.

    Can anyone please point me in the direction of some example or tutorial of a designer-friendly custom DataGridView? I'd be much obliged.



    Wednesday, January 21, 2009 3:33 PM
  • The DGV designer goes through a pretty lengthy process to determine if it needs to generate columns.  That process involves both AutoGenerateColumns and DataSource.  But I've had time to think about the problem and I think the solution might be pretty easy.  Why exactly do you need a designer for this control if the layout is predefined anyway? 

    You can disable the designer for the control either by adding a Designer attribute to your control and pointing it to a custom designer you wrote that doesn't do much. 

    I think a better solution might be to wrap the standard DGV in a user control instead.  This has many advantages for your case.  The biggest advantage is that you don't have to worry about the DGV designer anymore.  The second advantage is that you can expose only the properties you want to expose rather than all of DGV.  The third advantage is that you don't have to worry about default DGV values anymore. 

    Right now if you want your custom control to use, say, Blue for the foreground color you'll have to set the DGV's ForegroundColor property.  The problem with this approach is that, depening upon when the assignment occurs, the assignment will actually occur inside the form that hosts the custom control even though you do the assignment in your custom control directly.  This is because the designer generates assignments to any properties that do not have the correct default value.  Down the road if you decide to change the color to, say, Red then any existing forms will still use Blue due to the generated code.  With a UC the designer only generates (and sees) properties that you expose directly.  The nested DGV's properties must be set by you in code.  You can change the default value down the road without any problems.  More importantly is that you don't have to worry aboug AGC getting in the way since you can set the property in your nested version and the designer will never touch it.  Since you are using a highly customized grid it makes sense that others shouldn't be able to muck with the columns anyway. 

    Michael Taylor - 1/26/09
    http://p3net.mvps.org

    Monday, January 26, 2009 2:42 PM
  • I am having the same exact problem with VS2008 v9.0.30729.1 SP and .NET Framework v3.5 SP1.  Very disheartening. Whenever I open the form that contains this datagridview I notice that immediately the asterisk shows up on the filename tab indicating that the file has been changed and needs to be saved. This is before I touch the file.  I can open the “DataGridView Task” dialog and delete all of the extra columns that were added.  Then the next time that I open the file the same problem happens again.

    This happened at some time after I had deleted the DataGridView and added another one. There were many compile errors, because of bindingsource and other places in the program that were referring to the deleted DataGridView, until I renamed the new DataGridView to be the same as the previous one.

    At the same time I notice that I am more frequently not able to run this program with VS F5 as an error pops up reporting that: “Visual Studio could run because vhost.exe is in use” or something like that. Very strange.  It’s like some sort of reflection is happening and tying up the application file.

    Also I had deleted and re-added some Data Sources that are now used to fill a couple of binding sources that are used in this DGV, one for the main grid and one for a combobox column.

    Did that confuse you, as sure did confuse the designer.  I am considering deleting that DGV again and trying with a different one – yet I will wait on that because that may be the type of thing that is confusing the designer.  Maybe I will have to delete the DGV and the various binding sources and try again using different names.  I have worked on this form for couple of weeks and really do not want to start over.  I tried deleting all of the extra definitions that are added each time to the designer.cs file, as the ‘clicknclack’ poster here had done.  Either way deleting the extra duplicate columns using the designer “DGV Task” dialog or removing them by editing the designer.cs file – the problem comes right back.

    Currently I can delete those extra duplicate columns, build and run it and there is not a problem.  It is rather scary that I would have to do that and no way that we want to run our business.  There must be a way to fix this problem!!!!!!  I seem to recall seeing an option on a dialog where we could turn off auto-generate columns – maybe that was in an ASP.NET datagridview or somewhere else.
    Thursday, January 7, 2010 5:39 AM
  • The WinForm's version has an AutoGenerateColumns property but it is hidden in the Properties window.  You have to set it in code instead.

    The designer is not smart enough to tell the difference between property values you set via Properties/Designer and those you set in code because, after all, it just sees the underlying object.  Therefore the standard workaround is to ensure that you don't do anything inside the ctor that you don't want persisted in the source file.  If a property is changed in the ctor then it will eventually get coded into the designer file.  For forms the standard workaround is to postpone any databinding or modifications until OnLoad.  Controls don't have that option but I believe there is a similar method that gets called (can't remember the name).  Alternatively use the DesignMode property that all controls have to not do any property changes while in design mode. 

    Michael Taylor - 1/7/09
    http://p3net.mvps.org
    Thursday, January 7, 2010 2:08 PM
  • This problem may have to do with the fact that even though I have various fields set to "[None]" in the VS Data Sources tree, when we drag and drop a table item from the Document Sources window onto a form all of the fields are created in the resulting DataGridView.  The VS Designer seems to be ignoring the settings on these Data Sources tree where we have open the combo box on some field items and selected [None].

    When the VS Designer finds our DGV with less than a full set of fields for the table - then it adds a whole set of fields - not just the missing ones.  I am suspecting that if VS Designer was not ignoring the settings on the fields in the Data Sources tree that this problem may not happen.

    I found a few duplicate <metadata> items in the .resx file for this form.  I do not imagine that has anything to do with the DGV AutoGenerateColumns problems. I added a line immediately after this DGV object creation for AutoGenerateColumns = false and that does not seem to help - as others have reported.
    this.dataGridView2 = new System.Windows.Forms.DataGridView();
    this.dataGridView2.AutoGenerateColumns = false;
    I though about trying to remove some of these columns from the LINQ to SQL class definitions and I do not want to do that.  We use some of these fields in other places - and yet do not want to display them on this problematic DGV that won't quit adding another whole set of columns for this class each time that it is opened in the VS Designer!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!
    Thursday, January 7, 2010 2:25 PM
  • I tried making this AutoGenerateColumns virus go away by sprinkling some AutoGenerateColumns =  false in places and using a new class and still no luck.  I guess trying to hide it does not help.  The property is not virtual.  I am not smart enough to be able to imagine why this problem was invented.
    namespace RM.Acct.PS
    {
        public class DGVnoAGC : DataGridView
        {
            public DGVnoAGC()
            {
                base.AutoGenerateColumns = false;
            }
            public new bool AutoGenerateColumns
            {
                get
                {
                    return false;
                }
            }
        }
    }
    
    Thursday, January 7, 2010 3:58 PM
  • What is ctor?
    I tried this and still no luck:
    private void dataGridView2_AutoGenerateColumnsChanged(object sender, EventArgs e)
        {
            dataGridView2.AutoGenerateColumns = false;
        }
    

    This VS 2008 is crazy about adding those extra columns.  How can I ever get it to stop?
    I will look for we might do with that DesignMode setting - sounds difficult!
    Thursday, January 7, 2010 4:31 PM
  • ANSWER that worked for me!  There were a bunch of these .UserAddedColumn metadata in the .resx file for the form. Getting rid of those makes the DataGridView.AutoGenerateColumns virus stop happening!  None of the setting the AutoGenerateColumns = false or trying to subclass the DGV did any good.  The VS Designer was too persistant for any of those attempts.
      <metadata name="ID.UserAddedColumn" type="System.Boolean, mscorlib, Version=2.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089">
        <value>True</value>
      </metadata>
    
    • Proposed as answer by RannyMeier Thursday, January 7, 2010 5:10 PM
    Thursday, January 7, 2010 5:10 PM
  • I've been suffering with this same major annoyance for some time. I was excited by RannyMeiers last post, but unfortunately, commenting out the UserAddedColumn metadata fields did not work for me. Neither did setting the AutoGenerateColumns flag. Forms which use DGV control get duplicate columns added to them silently every time someone launches them in the designer. It's really annoying and dangerous. I hope this bug can get fixed as a matter of urgency. It's been around since at least 2008.
    Friday, August 20, 2010 2:35 PM
  • In the DatagridView Paint Event I wrote this first line:

     

    MyBase.AutoGenerateColumns = False

     

    For me it seems to work.

     

    I hope this help

     

    Friday, August 27, 2010 9:52 PM
  • Here's my work around for VS2008 DataGridView Autogenerating Columns bug.

    Delete the autogenerated columns except one.

    Set the one autogenerated column's visible=false.

     

    Friday, August 5, 2011 1:41 AM
  • Hi all ,

    Nice to see that Microsoft has had this issue around since 2005. The same bug is in the 2011 version also. It happens when you have multi tabs with DGV's on each one. Basically no rhyme or reason one thing I can say is that if the application runs on MAC which is a pain in the but to have 2 operating systems running the issue goes away. Run it in the MS Windows Mode and it is there the first time. Teyc suggest works but every once in a while the comboboxes in the DGV need to get reset to the datbinding source. Pass this to the Microsoft programming Technicians and have them take a look at their coding before it cont. into 2012 version of .Net Studio !!!!!!!!!!!

    Monday, September 12, 2011 4:05 PM
  • I had same problem.  I has subclassed the DataGridView control and was manually adding columns in the constructor. Like this:

    Public Sub New() InitializeComponent()     SetupGrid()    End Sub

    Protected Sub SetupGrid()    
        ColumnCount = 1     
        Columns(0).Name = "My column"  
    End Sub

    But that would result in extra columns getting added, the designer seems to get confused. So removed the call to Setup grid from the constructor, and changed it to a public method which I then call from my form constructor. Now the weird behaviour is gone.

    Basically the constructor and InitializeComponent methods in the subclassed grid cause weird things with the Designer. Making an explicit call to setup the grid after it has been constructed solved the problem for me:

    ' In subclassed dataviewgrid 'MyGrid':
    
    Public Sub New()
        InitializeComponent()
    End Sub
    
    Public Sub SetupGrid()    
        ColumnCount = 1     
        Columns(0).Name = "My column"  
    End Sub
    
    
    ' Then in Form1:
    
    Public Sub New()    
        MyGrid.SetupGrid
    End Sub
    

    Tuesday, July 17, 2012 10:22 AM
  • The designer has to call your ctor when it displays your control.  Therefore any code in your ctor will be executed.  If you change any properties of the control (including adding columns) then it is no different than if the user had done so in the designer.  When the designer needs to serialize out the changes it can't tell the difference so it'll serialize out any properties you set.

    There are a couple of correct approaches to solving this problem without having users of your control having to do anything.

    1) Wrap the code that should not run in the designer with !DesignMode.   This causes the code to only execute when not in the designer.

    2) Override one of the initialization methods that is only raised when the control is invoked at runtime.  For DGV I'd lean toward one of the data binding events.

    Tuesday, July 17, 2012 5:29 PM
  • It's hard to describe how incredibly disastrous this bug is. I just installed Visual Studio 2012 and to my despair it has not been fixed!

    For the forms and user controls affected by this bug, it seems the only reliable approach is to not use the designer: add columns and hook up the binding source in code. In my case, the bug only affects a handful of user controls, all of which inherit from the same base user control. A DataGridView is declared in each of the inherited screens. I have pored over all the code, and nothing I have tried makes any difference.

    Wednesday, October 10, 2012 7:53 AM
  • If you're making any changes to any properties in the ctor of the custom grid then you're going to have problems.  The designer cannot tell the difference between property changes in the UI vs property changes in the ctor.  For custom controls you have to follow the guidelines that all controls follow.  Any property initialization that has to occur and that should not be persisted in the designer must occur when the control is initialized at runtime.  One approach is to wrap the code in if (DesignMode).  This is especially important for data bound controls as you don't want the binding to occur in the designer since the data is probably not even there yet.  If you need examples then all the standard WinForms control implement the pattern correctly.  There are also lots of articles online about how to properly set up custom controls to work with the designer.

    I'm not aware of any bug in DGV that needs to be fixed so I don't know what you're looking for.  The only issue that I'm aware of is that DGV doesn't expose the property to auto generate columns in the Properties window but that is worked around by setting it explicitly in the custom control instead.  Beyond that, and if you're following the WinForms guidelines for writing controls, everything should work just fine.  It's been a while since I've had to create a custom DGV but I don't remember having any problems such that abandoning the designer was necessary.  But if you do want to go that route and you don't want someone from accidentally using it then you create define a custom designer that does nothing.  It is an attribute you'd put on your type.

    Michael Taylor - 10/10/2012
    http://msmvps.com/blogs/p3net

    Wednesday, October 10, 2012 3:25 PM
  • This bug is happening with standard DGVs. It is undoubtedly a bug; it's been reported in several other forums as far back as Visual Studio 2005. In my projects I have literally hundreds of forms and user controls with DGVs and 99% of them are perfectly fine, but I have six user controls which inherit from the same base user control which are infected with this bug. I am about to recreate the base user control from scratch to see what happens.
    Thursday, October 11, 2012 8:42 PM
  • I have recorded a screen capture showing the bug here: http://youtu.be/cf4nBITnNsI

    Do you still think it's not a bug?

    Thursday, October 11, 2012 11:30 PM
  • Without seeing the source code for your DGV and the form related code including how it is initializing and any event handlers you've hooked up I can't confirm it one way or the other.  Based upon your video you bound the grid to a source and then manually removed some columns.  But by default the grid is configured to auto populate the columns based upon the source.  Removing them from the UI might appear that it is doing something but if the designer decides that the source schema is out of sync with the columns it'll just add them back.  That is exactly the problem you're seeing as far as I can tell.  The AutoGenerateColumns property controls this.  The "bug" that I'm aware of is that this property isn't exposed in the Properties window for some reason so you have to explicitly set it to false if you want to use a source in the designer and do not want to auto refresh the columns.  I'm also vaguely remembering that there was at one point a problem where setting the DataSource property would reset AGC but I can't remember off the top of my head whether it still occurs or not.  If it does then the solution would be to override the DataSource property and set AGC to false, IIRC.

    Thursday, October 11, 2012 11:50 PM
  • Watch the video again, I have added annotations. When the DGV is hosted on the user control, and not on the protected inherited panel (a standard WinForms panel with a single label on it), the columns do not auto-generate after each build. The designer.cs file has AutoGenerateColumns = false, like every other DGV in this solution. I'm not handling any DGV events. When the DGV is moved to the inherited panel, build the solution, and the deleted columns are regenerated. The DGV was dragged onto the user control as you would normally expect. The DGV.DataSource is a BindingSource. The BindingSource.DataSource is a business object which inherits from BindingList<T>. DesignMode is checked before assigning the data source. You can see plainly that the behaviour is different depending on which control is hosting the DGV. This is exactly the problem that others have reported on this forum and elsewhere. Of course, this not the only way that the problem rears its ugly head, but it illustrates the bug. It's a bug, no question. It's difficult to reproduce from scratch, but it seems to be even harder to fix once it's happened. No one knows how to fix it.
    Friday, October 12, 2012 6:15 AM
  • The video doesn't show anything useful.  It likely boils down to your code.  This is more likely since you have this problem on only 1% of the DGVs you use.  I've never had or seen this problem myself.  If you feel this is a bug in the framework and not in your code then submit the bug to MS via the Feedback Tool.  In order for them to acknowledge it as a bug you're going to have to provide them sample code that replicates the issue.  If you have that code then send it to them and they can prioritize it.  I'm afraid there is nothing I can do for you here as I don't see this problem myself.  This is related to the WinForms Designer more than the IDE so I'm moving this thread.  Maybe somebody over there can provide you better assistance.  Good luck.
    Friday, October 12, 2012 2:50 PM
  • I have reduced the solution down to a 21KB sample. If you think it's my code, I'd really appreciate your input. The solution can be downloaded here: https://connect.microsoft.com/VisualStudio/feedback/details/767380/datagridview-columns-auto-generate-in-designer-after-build

    Build the solution, open the ScreenBizObjectsEdit designer and follow the same steps as shown in the video.


    Sunday, October 14, 2012 11:22 PM
  • I can now reproduce the problem at will. It happens when you have a protected inherited BindingSource as the DGV.DataSource and the DGV is on a protected inherited panel. Steps to reproduce:

    1. Create a user control UserControl1 with a protected BindingSource and a protected panel;
    2. Create a user control UserControl2 inheriting from UserControl1;
    3. Set the protected BindingSource data source to any business class in the solution;
    4. Drag a DataGridView to UserControl2 (not to the inherited panel);
    5. Set the DataGridView data source to the inherited BindingSource;
    6. Remove one or more columns from the DataGridView;
    7. Build the solution and the selected columns should remain;
    8. Move the DataGridView to the protected panel;
    9. Build the solution and all of the columns are regenerated.

    Or download the sample at http://connect.microsoft.com/VisualStudio/feedback/details/767380/datagridview-columns-auto-generate-in-designer-after-build

    Monday, October 15, 2012 1:39 AM
  • This issue is not specific to the datagridview and its columns. If you set others properties of your object, they will also be copied by the designer in the Initialize component of the final form (or custom control).

    Most of time, this not an issue as it just reassign the same value of the property. But when you create column for the datagridview this behavior become a problem.

    In fact it is a programming bad practice.

    Using Inheritance for setting properties is a bad practice, inheritance should be used for adding functionality or overriding the behavior of current one.

    If you want to make this kind of customization you should use usercontrol instead or using a shared function which configure you gridviewproperty on runtime.

    The AutoGenerateColumns property allow the datagridview to regenerate the column from the exposed properties when the datasource Type change. You could change the property of the generated column by setting some attributes to the property of your datasource object. It's a mess that this property is not shown in the designer but it has no relation with the base problem of this topic.

    Thursday, July 17, 2014 7:59 AM
  • May be it is too late, but I hit the same roadblock today. Tried everything from this thread, nothing worked. Finally found solution that looks ugly but works so far:

        public partial class StateView : DataGridView
        {
    
            public StateView()
            {
                InitializeComponent();
    
                InitColumns();
                this.AutoGenerateColumns = false;
            }
    
            private bool m_ColumnsCreated = false;
            private void InitColumns()
            {
                if( m_ColumnsCreated )
                    return;
                // Populate columns here...
                m_ColumnsCreated = true;
            }
    
            protected override void OnColumnAdded( DataGridViewColumnEventArgs e )
            {
                if( m_ColumnsCreated ) {
                    Columns.RemoveAt( Columns.Count - 1 );
                    return;
                }
                base.OnColumnAdded( e );
            }
    }
    The idea is to block any column addition called after constructor complete. It may not work in design mode - although in design I have no problem. But works just fine at runtime.

    Thursday, October 29, 2015 11:17 PM
  • For information:

    This is probably because the designer doesn't do that until you change something on the form.

    So opening it to look at doesn't cause the problem, just editing it.

    Friday, October 25, 2019 4:36 AM