Updated Modern Code Generation for WinForm’s InitializeComponent
When you create a WinForms Form or User Control with the WinForms Designer inVisual Studio, it does not have a special definition or file format like XML orHTML to represent the user interface. From the beginning, the only formatWinForms has used is program code. A Form or User Control defined in a WinFormsVisual Basic project gets saved into VB Code. In a C# project, that is C# code.That code will be placed in a dedicated Designer file, which sits behind theactual Form code file and contains the code to control the UI.
When your Form or User Control needs to be opened again inside of the WinFormsDesigner, that code is interpreted and – based on the resulting object graph –the Form/User Control gets recreated in the Designer. That is the reason we callthe process of saving a Form CodeDOM serialization.CodeDOMhere refers to an object model (the Code Document Object Model)which allows the developer to define aspects of a program or part of a programby objects of certain types.
While CodeDOM is pretty flexible, can be extended comparatively easily andsupports more languages than Visual Basic or C#, generating a CodeDOM graph froman existing code file is a completely different beast. And although CodeDOMhas the option to actually write a code file for particular languages throughits existing Compilerimplementation,the style of that resulting code is the same it has been from the beginning of.NET Framework, which is in many cases no longer up to current coding standards.
In WinForms, when you design a Form, everything which is relevant is generatedin one method per Form or User Control. That method (amongst a bit ofinfrastructure and initialization code in addition) is calledInitializeComponent
.
This method is called by a Form’s constructor unconditionally. In the C# casethat’s pretty obvious, where a new Form which you add to your project, alwayshas that constructor and the required call:
public partial class Form1 : Form
{
public Form2()
{
InitializeComponent();
}
}
In Visual Basic, if you don’t add a constructor Sub New
explicitly, the VisualBasic compiler inserts the call to InitializeComponent
automatically in thebackground. If you however add a constructor to the code file, the editor alsoinserts the call to InitializeComponent
in the VB code:
Public Class Form1
Sub New()
' This call is required by the designer.
InitializeComponent()
' Add any initialization after the InitializeComponent() call.
End Sub
End Class
Note that in Visual Basic, the
Inherits
statement, which lets your new Formclass inherit from theSystem.Windows.Forms.Form
base class, in contrast to C#is only part of the Designer code behind file. In VB it’s also sufficient for apartial class only to state thePartial
keywordin one of the partial class’ code files. That is the reason why a Visual BasicWinForms Form code file does not contain anything but the Form’s classdefinition by default.
Up to recently, the WinForms Designer used the CodeModelInterfaceto interpret source code of the different programming language to build therequired internal CodeDOM graph for the Designer to hold a Form’s or a UserControl’s definition. But we changed that.
Enter Roslyn
WinForms introduced with Visual Studio 2022 version 17.5 a modernized way toread and generate the code for InitializeComponent
for the WinFormsOut-of-ProcessDesigner.It does so by using the APIs of the .NET CompilerPlatform – better knowas the Roslyn SDK – for all related tasks. The Roslyn Compiler is a set ofopen-source compilers and code analysis APIs for .NET languages. It allowsdevelopers to write, analyze, and manipulate code in C# and Visual Basic .NETusing modern language features. It also provides a rich set of diagnostic andcode refactorings to improve code quality and developer productivity. It is thegold standard and the current best practice for code generation in C# and VB.And, since it’s the same tooling that is used for compilation and build purposesinside Visual Studio for any C# or Visual Basic project its code generationresult is completely in-line with current coding standards.
Also, since the Roslyn compiler provides certain APIs to not know only about thecorrect syntax of a particular statement, command or method, but also about thesemantics of a code block already at WinForms design time, the WinForms designercan point out potential problems with the code inside of InitializeComponent
far earlier and more precisely than before. So, it not only knows when you’vespelled ‘Buttne’ wrong – it would also know that a variable with a typo definedinside of InitializeComponent
would be an unknown symbol, and be able to pointthat out.
But there is a series of additional benefits:
- Previously, the CodeModel based building up of the CodeDOM could only run onthe UI Thread. That was not only a blocking operation, it couldn’t utilize thefull potential of a modern, multi-core processor. Using the Roslyn compiler,we will be able to optimize the building process over time by usingparallelization.
- The old system didn’t have an easy way to interpret more recently introducedlanguage features. Using Roslyn, we will have the option to introduce languagefeatures like
NameOf
to generate more robust code, especially for databinding purposes. In addition it opens up the path to more complex codegeneration inside ofInitializeComponent
in the future, which will help tooptimize and equalize code generation for HighDPI scenarios generated onmachines with different HighDPI settings. - The Roslyn compiler honors many aspects of .editorconfigconfigurations,so the code generated in
InitializeComponent
is close to what you and yourteam are enforcing as your coding standards by custom .editorconfigdefinitions.
That all said, there are a couple of coding elements which are fundamentallydifferent than before. The omission of this
in C# or Me
in Visual Basic isone of such an example. The following screenshot shows the difference in thecode generation with Roslyn for a Button in InitializeComponent
:
If you’re interested in a more technical background about moving the codegeneration in the WinForms designer to Roslyn or how to configure theInitializeComponent
code generation with .editorconfig, take a look at thistechnical article in the WinFormsrepowho points out all those things in greater detail.
Feedback about the subject matter is really important to us, so please let usknow your thoughts or ideas you might have around WinForms code generations inthe comments. If you have suggestions around the WinForms Designer or think youfound a bug, feel free to file new issues in the WinForms Githubrepo.
Happy designing and coding!
26 comments
Thanks for all the great efforts you guys are putting in WinForms! WinForms are getting better and better.
I hope the .net 8 will also fix some of the missing highDpi scenarios… it’s a problem now to develop in a team where each developer has his own screen resolution… you never know what will happen 😁
Thank you! We’re working hard on highDPI scenarios, though there are many challenges to it given our original design targeting 96dpi single monitor scenarios. I sure didn’t have any idea we’d be where we are hardware-wise back then 😂. You can keep track of our progress throughout .NET 8 previews at https://github.com/dotnet/winforms – we’re very interested in your feedback about current changes and about what specific problems your apps are facing. I can’t promise timelines but I can promise that customer reported issues are prioritized in the pile of highDPI issues as we are working on the general area.
~Merrie McGaw, lead WinForms Engineering team
Having the DOM as code rather than some esoteric language was a great idea and a shame that WPF and now MAUI left it behind. Glad to see you guys continue to invest here!
Definitely! This is what I dislike the most about WPF and MAUI – the arcane extra language one has to learn, and map back to familiar concepts, for no good reason at all.
It’s horrible to define object model in an imperative way instead of declarative way, if the code is expected to be understood by some tool.
Thanks for this update. It’s really nice see WinForms evolving! I would like to know where should I report problems for issues on this matter, for example, I’m getting wrong serialization (and compiler error) when I select a project resource instead local resource (in VB). I also have intereset in using my skills to try contribuite fixing this kind of bug.
The best way to report issues with the .NET Out-Of-Proc Designer or contribute in general to WinForms is via our GitHub Repo:
https://github.com/dotnet/winforms
Thanks,
Klaus
To add to the comment Klaus made – sometimes we get a little bit more logging and diagnostic information if you file a feedback ticket through Visual Studio. That said, we’re more than happy to work with you either way you choose to communicate – we are just happy to have the feedback so we can address the most pressing problems faster 🙂.
~Merrie McGaw, WinForms engineering team lead.
could be leave a way to call custom Method from InitializeComponent,between SuspendLayout and ResumeLayout.
because some winform control not stable.so let use write code to design the UI is very important !
Designers don’t have the flexibility to handle everything. Usually the code is more controllable.
WinForm would be great if I implemented my request, because it would be possible to write the UI code while watching a preview in the designer of the code changes.
I am not entirely sure what you mean, or to what end you want to do that, but for a more controlled initialization of components or controls, you can use ISupportInitialize. That’s used for components with depending properties, where the order in which the writing of properties takes place, does matter. Basically, your control will be informed when the initialization starts and when it ends. In the meantime, for the properties in question, you are not actually assigning the properties internally, but you cache their values for the time being, until the initialization is over. Then, you assign what you collected so far in the order for those properties, which need an “ordered” handling.
Meanwhile WPF team: zzzZZZZzzzz
It isn’t that bad, at least it has a designer, Blend support, DirectX support exposed to .NET and XAML, form validation, and not 3000 bugs and counting, as WinUI.
@Max
I would encourage you to follow their github, their roadmap with some information was updated recently – https://github.com/dotnet/wpf/blob/main/roadmap.md
Sigh…whilst i love to see the improvements to WinForms, i would also love to see a similar investment in WPF. I keep saying it but why would anyone embrace new Microsoft technology (i.e. MAUI) when Microsoft have demonstrated as soon as something new and shiny comes along they will drop you.
One thing which I don’t think has been addressed (and so apologies if I missed it) is to what flavour of WinForms this supports – is it global, irrespective of .NET Framework or .Core, or is it tied only to .NET 5+?
The mention of the out of process designer hints that this is 5+ only.
Thanks;
Richard Moss
We could address this also in the Out-Of-Proc Designer for .NET Framework, which we are working on to address issues in 64-Bit Visual Studio 2022 and really old WinForms apps, which still rely on 32-Bit-only (often) COM based components. But we figure that it would too much of a mismatch between the style of generated code with the in-proc and the out-of-proc Designer, so this feature probably only makes sense for WinForms apps going forward to .NET 6,7,8+ to begin with.
I really would like to see it in .NET framework also, especially binding code generated with the use of NameOf.
We want to upgrade to .NET 6,7,8+ but we need (and waiting) the new OOP designer to reach to parity of functionality of .NET framework one.
It’s quite nice to see more work being done on the WinForms front.
My only complaint is how high DPI is handled when designing. Currently, I have to to make Visual Studio DPI unaware in order to do any edits to my forms/controls. The ‘switch to 100%’ doesn’t work well for me, so in the end I have to disable DPI awareness. It would be nice (and easier on my old, tired eyes) if WinForms could handle high DPI automatically when designing without having reboot Visual Studio, or having to disable its DPI awareness.
Just a litle TipEx I noticed, the C# Code of Has a Class with then Name ‘Form1’ and the Konstructor is call ‘Form2’.
This should also be Form1
Sorry, didn’t catch all “greatness” of improvements. I see you simply get rid of unnecessary “this.” and at last start using namespaces instead of full naming. IS IT ALL?!?! What about most ugliest idea – to keep design(!!!) of form in CODE?? It’s totally stupid even for 200* years!
Design is declaration – like XML, JSON, whatever. Why MS still keeps old shity code for WinForms? You had to move at least to XML! (like it happen with WPF)
“WinForms introduced with Visual Studio 2022 version 17.5 a modernized way to read and generate the code for InitializeComponent for the WinForms Out-of-Process Designer. It does so by using the APIs of the .NET Compiler Platform – better know as the Roslyn SDK – for all related tasks.”
Perhaps this explains the frequent failure of 7.5 to render the Design View … with odd visual results and/or no error messages, or strange error messages ?
I have been working in C# WinForms and VS from 2002, but, I must be on another planet where what the author refers to as “code” in the Designer.cs files is as fat/thin as XML/XAML, or, any other descriptive “recipe” for serializing/rendering the attributes, properties, events, etc., of an interface … Just as event binding can be done in XAML, it is done in Designer files.
In my experience, Visual Studio as an IDE for WinForms C#, has seriously degraded in usefulness over the last six months of “updates:” the current so-called “intellisense” out of control, etc.; frequent failures of ToolBox and Property browser windows to show content; frequent/repeated reloading of “symbols” as the app is run.The failure to address high DPI issues over years is mentioned already
Just use AvaloniaUI, instead.
It has none of those issues.
By all means: The work, we are doing here is not aimed at making WinForms a new UI stack with a completely changed design paradigm. It is primarily for the millions of existing lines of WinForms code of those Line of Business Apps which exist pretty much since that year your mentioned yourself. They’ve often reached their size over the last 21 years, and with it a point where only the WinForms Designer itself can become the path to a feasible modernization. By feasible I mean: In many cases, you don’t throw away 5 million lines of WinForms code and write them based on a different UI stack from scratch. Instead, what we can do or offer is help with a modernized WinForms tooling to bring Apps forward from .NET Framework to .NET (6,7,8+) and help modernizing them along the way. That’s what this effort primarily is about. But we of course can’t break existing paradigms completely. And to add on that, if it comes to Windows Apps: the way WinForms works is still an extremely popular RAD Design-tool for a particular kind of domain-specific LOB Apps, which can be used extremely effective without long ramp-up time. Of course, it’s for special target audiences – Developers and Users – and there are, contrast to 20 years ago, a lot of more alternatives. But I never saw a problem in the co-existance of WinForms and WPF 15 years ago – and I certainly don’t now, where we have WinUI, .NET MAUI, Razor, Blazor, etc. in addition.
Sure, there might be bugs in new tooling that we don’t know about yet. Please help to make them actionable for us, so we can address them.
This is an ongoing effort for WinForms, both in the Designer and in the runtime, not only since .NET 7. We’re constantly delivering updates to address issues in PMV2, a HighDpi mode, which wasn’t really thought of at the time of the first version of WinForms, which was originally targeted to run on Windows 98 and ideally on Windows 2000. So, it’s taking some time to carefully modernize in this area, again, without breaking the millions of existing WinForms apps, which people are considering bringing forward with .NET 6,7,8+.