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
- Anonymous
April 28, 2004
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? - Anonymous
April 28, 2004
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 - Anonymous
April 28, 2004
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? - Anonymous
April 28, 2004
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. - Anonymous
April 28, 2004
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. - Anonymous
April 28, 2004
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. - Anonymous
April 28, 2004
You're correct Paul, that's how it works. Hand editing the .designer.cs file is considered "bad" in nearly all situations :) - Anonymous
April 28, 2004
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. - Anonymous
April 28, 2004
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. - Anonymous
April 28, 2004
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. - Anonymous
April 28, 2004
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. - Anonymous
April 29, 2004
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. - Anonymous
April 29, 2004
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? - Anonymous
April 30, 2004
What is this?
A Google search returns only your page. - Anonymous
April 30, 2004
Rich: This is something we're working on improving. Thanks for the feedback. - Anonymous
April 30, 2004
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. - Anonymous
May 03, 2004
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(). - Anonymous
May 03, 2004
Rovert: I don't know. I'm still trying to get an answer for that one. - Anonymous
May 06, 2004
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? - Anonymous
May 08, 2004
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? - Anonymous
May 26, 2004
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! - Anonymous
May 26, 2004
Rovert: I'll ping folks on that again. - Anonymous
August 08, 2004
Ping Back来自:t_jian的专栏 - Anonymous
August 25, 2004
Ping Back来自:blog.csdn.net - Anonymous
January 16, 2005
Ping Back来自:blog.csdn.net - Anonymous
January 25, 2005
Ping Back来自:blog.csdn.net - Anonymous
February 22, 2005
Ping Back来自:blog.csdn.net