Winforms designed code and C# partial classes


In Whidbey, the WinForms designer takes advantage of a new C# language feature called “partial classes”.  This allows them to pull out the designer generated code into a separate file.  It has several advantages:


·         Users are less likely to muck with it, since it’s in a different file.  When users start to edit designer generated code, things break down pretty quickly.  It’s pretty common for the designer to eat code it doesn’t understand, causing you to lose your work.


·         The code generator can use no ‘using’ directives, instead having only fully qualified names (FQN).  It’s a good idea for code generators to use FQNs, because it makes them resilient to unforeseen changes in the compilation environment (like someone adding a class named “System”


·         It reduces clutter in the user file, letting you focus on your work.


 


To show what this looks like, I created a simple C# Windows Application, and added an OK button.  Here is the result:


 


——- program.cs ——-


#region Using directives


 


using System;


using System.Collections.Generic;


using System.Windows.Forms;


 


#endregion


 


namespace WindowsApplication1


{


    static class Program


    {


        /// <summary>


        /// The main entry point for the application.


        /// </summary>


        [STAThread]


        static void Main()


        {


            Application.EnableVisualStyles();


            Application.EnableRTLMirroring();


            Application.Run(new Form1());


        }


    }


}


——- Form1.cs ——-


#region Using directives


 


using System;


using System.Collections.Generic;


using System.ComponentModel;


using System.Data;


using System.Drawing;


using System.Windows.Forms;


 


#endregion


 


namespace WindowsApplication1


{


    partial class Form1 : Form


    {


        public Form1()


        {


            InitializeComponent();


        }


    }


}


——- Form1.Designer.cs ——-


namespace WindowsApplication1


{


    partial class Form1


    {


        /// <summary>


        /// Required designer variable.


        /// </summary>


        private System.ComponentModel.IContainer components = null;


 


        /// <summary>


        /// Clean up any resources being used.


        /// </summary>


        protected override void Dispose(bool disposing)


        {


            if (disposing && (components != null))


            {


                components.Dispose();


            }


            base.Dispose(disposing);


        }


 


        #region Windows Form Designer generated code


 


        /// <summary>


        /// Required method for Designer support – do not modify


        /// the contents of this method with the code editor.


        /// </summary>


        private void InitializeComponent()


        {


            this.buttonOK = new System.Windows.Forms.Button();


            this.SuspendLayout();


//


// buttonOK


//


            this.buttonOK.Anchor = ((System.Windows.Forms.AnchorStyles)((System.Windows.Forms.AnchorStyles.Bottom | System.Windows.Forms.AnchorStyles.Right)));


            this.buttonOK.Location = new System.Drawing.Point(205, 238);


            this.buttonOK.Name = “buttonOK”;


            this.buttonOK.TabIndex = 0;


            this.buttonOK.Text = “OK”;


//


// Form1


//


            this.AutoScaleBaseSize = new System.Drawing.Size(5, 13);


            this.ClientSize = new System.Drawing.Size(292, 273);


            this.Controls.Add(this.buttonOK);


            this.Name = “Form1”;


            this.Text = “Form1”;


            this.ResumeLayout(false);


 


        }


 


        #endregion


 


        private System.Windows.Forms.Button buttonOK;


    }


}


 


————————–


 


What do you think of the new default template?  It’s an improvement, no?

Comments (29)

  1. Jeremy says:

    I don’t get it.

    How do Form1.Designer.cs and Form1.cs relate? I mean what ties the two together because I don’t see them reference each other.

    Is it only because they both have an implementation of Form1 class and C# magically melds them together?

    Also if C# is a standards based language how do you just go ahead and add ‘partial’ to it?

  2. jaybaz [MS] says:

    Jeremy: They are tied together because they are the same class. (They have the same FQN.)

    ECMA owns the C# standard. The committee evolves the language on an ongoing basis. Read more:

    http://msdn.microsoft.com/net/ecma/

    http://www.ecma-international.org/publications/standards/Ecma-334.htm

  3. Jeremy says:

    Ok gotcha. So because both are WindowsApplication1.Form1 the compiler ties them together. Nifty!

    Regarding C#, I realize it is an ECMA standard, but if I look at that standards doc I see no mention of the keyword ‘partial’. So is that a MS extension or what?

  4. jaybaz [MS] says:

    The code I posted is based on Whidbey (aka Visual Studio 2005). It’s pre-release, and includes a compiler & designer that implement the proposed C# 2.0. ECMA is still considering the proposal.

  5. Paul says:

    I assume that any generated code for "Clicks", and other events would be in the Form1.cs file?

    If not, you are back to the user editing code in the "designer" file.

  6. jaybaz [MS] says:

    Paul: that’s correct. I considered including an event in my sample, but I didn’t want it to get too big to read easily.

  7. Julien Ellie says:

    You’re correct Paul, that’s how it works. Hand editing the .designer.cs file is considered "bad" in nearly all situations :)

  8. Paul says:

    Thanks,

    Thats the response I was hoping you were going to give. But it does now say that the generator is touching the Form1.cs file instead of being isolated to the "designer file".

    With anonymous clases you could also go more to a command pattern instead of a new btn_click method on Form1.cs. I am not sure what that would buy you in this case, but it would be possible. Java tends towards the anonymous inner classes for event handlers. Its just a thought.

    Thanks.

  9. jaybaz [MS] says:

    Yes, it’s bad. The designer is quickly frustrated by code it didn’t create.

    Part of the distinction between "Elvis" and "Mort" is that Elvis sees designers as just a view on his code, while Mort sees the designer as what he’s actually working on. Elvis thinks the generated code is his, Mort does not.

    By creating a situation where the typical C# user can’t freely edit this code, we’re failing to meet users needs.

  10. Paul says:

    The key as always is an educated consumer.

    Hints like "// place code here" help, but you still end up with problems when the coder deletes the generated "event" method, and forgets to clean up the += on the control.

    Or conversely if the coder unhooks the event, the method stays around as dead code until the coder remembers to delete it.

    The designer can never be 100% correct on round trips, just so long as it is predictable and consistant an educated coder should be fine with it.

    Generated inner classes might be an interesting idea to explore though for a cleaner way to isolate the generated code.

    Thanks.

  11. Mitch Walker says:

    What about the protected Dispose method? What if I need add implementation to that function. I am back to editing the designer file. The protected Dispose method should be implemented in the Form1.cs file. I don’t believe the designer ever modifies it.

  12. Rich says:

    I like the template – I dont like it in the project system – it’s harder to work with. The designer files are hidden away (you have to do show all files to see them). The project should always show the [+] sign.

  13. Leo says:

    This generally looks good. But another area has not been talked about: the .resx files.

    In the current version (VS.NET 2003), the designer will destroy any custom entries in the .resx file belonging to a form whenever you edit the form (it seems to completely rewrite the file everytime).

    This makes it a pain to use the default resources for localizing strings that the form uses (e.g. for messagebox message etc.), because you custom strings are deleted everytime you open the form. :-(

    So you either have to create another class to hold your strings or handle all the resource business yourself.

    Are there plans for partial resource files or something like that as well?

  14. Rovert Prohaska says:

    What is this?

    A Google search returns only your page.

  15. jaybaz [MS] says:

    Rich: This is something we’re working on improving. Thanks for the feedback.

  16. jaybaz [MS] says:

    Leo: As much as I’d like to have a designer that could safely roundtrip your code 100% of the time, that’s not happening any time soon. IMO, we’re not even close.

    The string you show in a MessageBox is not part of the current form, I think. Anyway, the right place for it is a project resource file.

    In Whidbey, resgen.exe should have some smarts for generating a typesafe way to access your resources. Long overdue, IMO.

  17. Rovert Prohaska says:

    Can you please tell me what the secret method

    Application.EnableRTLMirroring() does? I have looked around and have not found any docs on this.

    You are using Application.EnableRTLMirroring(); in your Main().

  18. jaybaz [MS] says:

    Rovert: I don’t know. I’m still trying to get an answer for that one.

  19. Jeremy Marsch says:

    I noticed one thing that looked a little weird: The Dispose method goes into the generated portion of the partial form.

    Now, this might not be highly applicable to a Form (because you should be putting resource control code in another class etc), but what if, for whatever reason, you needed to put some code into the Dispose method?

  20. Steve Wart says:

    I’m confused. Can I create a partial classes in two different assemblies and merge them together when they’re loaded?

    Otherwise, why doesn’t the Designer just put the generated properties into a resource file? What’s the point of further complicating the C# compiler when this is something that could be better provided in the CLR?

    How does this fit in with the Avalon/XAML vision of separating application functionality from the presentation layer?

  21. Rovert Prohaska says:

    I found out that this has something to do with ‘right to left’ languages like some middle-eastern languages (hence the RTL) and mirroring the layout of the widgets on the form (not the language text itself.)

    If you could find out more about this, I would be appreciative.

    Thanks!

  22. jaybaz [MS] says:

    Rovert: I’ll ping folks on that again.

  23. t_jian says:

    Ping Back来自:t_jian的专栏

  24. sheercony says:

    Ping Back来自:blog.csdn.net

  25. sunsnow8 says:

    Ping Back来自:blog.csdn.net

  26. gotoxqc says:

    Ping Back来自:blog.csdn.net

  27. tominsight says:

    Ping Back来自:blog.csdn.net