The Windows Forms (WinForms) Team has been working hard over the last few Visual Studio release cycles to bring the WinForms designer for.NET applications up to equivalence with the.NET Framework designer. As you may know, a new WinForms designer was required to support.NET Core 3.1 and later.NET 5+ apps. As a result of the differences between.NET and the.NET Framework-based WinForms designer that everyone knows and loves, the task necessitated a near-complete redesign of the designer. The purpose of this blog post is to provide you with some information on the new architecture and the changes made. And, of course, how those changes will affect you when you develop custom controls and.NET WinForms apps.
After reading this blog post, you should be familiar with the fundamental difficulties that the new WinForms designer is intended to answer, as well as have a high-level grasp of the major components of this new approach.
How far have we come?
While we intended for perfect parity between the OOP designer and the.NET Framework designer for the release of Visual Studio 2022, we still have a few items on the queue. Having said that, the current generation of the OOP designer already has the majority of the substantial enhancements at all essential levels:
Performance: Beginning with Visual Studio 2019 v16.10, the performance of the OOP designer has been significantly enhanced. We tried to enhance the experience of interacting with controls on the design surface, such as selecting and moving controls, by lowering project load times.
Databinding Support: WinForms in Visual Studio 2022 introduces a more simplified method to handling Data Sources in the OOP designer, with a focus on Object Data Sources.
This new method is exclusive to the OOP designer and.NET-based apps.
Extensibility SDK for WinForms Designer: Because of perceived differences between the OOP designer and the.NET Framework designer, producers of third-party controls for.NET will need to use a special WinForms Designer SDK to construct bespoke Control Designers that run in the context of the OOP designer.
An inside peek at the WinForms designer
Designing Forms and User Controls using the WinForms designer reveals a few surprises to those who delve under the hood for the first time:
1. The layout is not “saved” (serialized) by the designer in XML or JSON. It directly serializes the Forms/User Control description to code — in the new OOP designer, which is either C# or Visual Basic .NET When a user places a Toggle on a Form, the code for generating the Button and assigning its properties is created into the Form’s ‘Initialize Component’ function. When you open the form in the designer, the ‘Initialize Component’ function is parsed, and a shadow.NET assembly is built on the fly from that code. This assembly includes an executable version of ‘Initialize Component,’ which is loaded in the designer’s context. The ‘Initialize Component’ function is then called, and the designer can now see the resultant Form with all of its control definitions and given properties. This type of serialization is known as Code Document Object Model serialization, or Code DOM serialization for short. This is why you shouldn’t directly modify ‘Initialize Component’: the method will be overridden the next time you visually alter something on the Form and save it, and your changes will be lost.
2. Every WinForms control has two code layers. The code for control that executes during runtime comes first, followed by a control designer that regulates the behavior at design time. The functionality of the control designer for each control is not incorporated in the designer itself. A specialized control designer, on the other hand, works with Visual Studio services and features.
We encountered a significant issue when we chose to offer apps developed on.NET Core 3.1 and.NET 5+ in the original designer. Visual Studio is built on the.NET Framework, but for projects that target a different runtime, it must round-trip the designer code by serializing and deserializing it. While you can run.NET Framework-based types in.NET Core/.NET 5+ programs with some restrictions, the opposite is not true. This is known as the “type resolution problem.” The Textbox control is a fantastic illustration of this: in.NET Core 3.1, we added a new property named ‘Placeholder Text.’ That property does not exist on ‘Textbox’ in the.NET Framework.
Furthermore, during design time, a Form with all of its controls and components renders itself to the designer. As a result, the code that instantiates the form and displays it in the Designer window must be executed in.NET rather than.NET Framework, so that newer properties available only in.NET also reflect the actual appearance and behavior of the controls, components, and, eventually, the entire Form or User Control.
Because we intend to keep developing and introducing new features in the future, the situation will only worsen. As a result, we needed to create a method that allowed for such cross-framework interactions between the WinForms designer and Visual Studio.
Navigate to the Design Tools Server.
Developers must view their Forms in the designer exactly as they will appear at runtime (WYSIWYG). The Code Dom serializer must execute in the context of the version of.NET the project is targeting, whether it be the ‘Place holder Text’ property from the previous example or the layout of a form with the appropriate default font. And we obviously can’t do that if the Code Dom serialization is going concurrently with Visual Studio. To address this, we execute the designer outside of the process (thus the name Out of Process Designer) in a new.NET (Core) process named DesignToolsServer. The DesignToolsServer process uses the same.NET version and bitness (x86 or x64) as your application.
When you double-click a Form or a User Control in Solution Explorer, Visual Studio’s designer loader service detects the.NET version and creates a DesignToolsServer process. The designer loader then transfers the code from the ‘Initialize Component’ function to the DesignToolsServer process, which can now
operate under the desired.NET runtime and deal with every type and property the runtime supports.
While exiting a process solves the type-resolution problem, it poses a few new problems in terms of user interaction inside Visual Studio. For example, consider the Property Browser, which is included with Visual Studio (and therefore also .NET Framework-based). It’s designed to show the.NET Types, but it can’t since the Code Dom serializer can’t (de)serialize .NET types.
Control Proxies and Custom Property Descriptors
To enable interaction with Visual Studio, the DesignToolsServer presents proxy classes for form components and controls developed in the Visual Studio process, in addition to the genuine components and controls on the form created in the DesignToolsServer.exe process. An object proxy is constructed for each one on the form. While the actual controls are located in the DesignToolsServer process, the object proxy instances are located in the client — the Visual Studio process. If you now pick an actual.NET WinForms control on the form, Visual Studio will select an object proxy instead. And that object proxy does not have the same attributes as its server-side counterpart control.
It instead translates the control’s properties 1:1 with new proxy property descriptors that allow Visual Studio to communicate with the server process.
So, clicking on a button control on the form now causes the following (simplified) series of actions to occur in order for the properties to appear in the Property Browser:
1. The mouse click occurs in the Visual Studio process on a unique window known as the Input Shield. It’s a sneeze guard if you will, and its sole purpose is to intercept mouse messages sent to the DesignToolsServer process.
2. The mouse click is received by the DesignToolsServer and forwarded to the Behavior Service. The Behavior Service locates the control and forwards it to the Selection Service, which performs the appropriate processes to choose that control.
3. During that process, the Behavior Service also locates the corresponding Control Designer and takes the appropriate processes to allow that Control Designer to render any adorners and glyphs are required for that control. Consider the preceding Split Panel example’s Designer Action Glyphs or custom selection marks.
4. The control selection is reported back to Visual Studio’s Selection Service through the Selection Service.
5. Visual Studio now understands which object proxy in the DesignToolsServer corresponds to the specified control. The object proxy is chosen by the Visual Studio selection service. This causes the values of the chosen control (object proxy) in the Property Browser to be updated once again.
6. In turn, the Property Browser searches the Property Descriptors of the chosen object proxy, which are mapped to the proxy descriptors of the real control in the DesignToolsServer’s process. So, for each property that the Property Browser needs to update, it does Get Value on the corresponding proxy Property Descriptor, which results in a cross-process call to the server to obtain the real value of that control’s property, which is then shown in the Property Browser.
Features that will be added in the future and those that will be taken off
While we have almost reached parity with the.NET Framework Designer, there are still a few places where the OOP Designer needs improvement:
1. The Tab Order interaction has been developed and is being tested. This functionality will be available in Visual Studio 17.1 Preview 3 when it is released. Apart from the Tab Order feature now included in the.NET Framework Designer, we intend to expand the Tab Order Interaction, making it simpler to reorder, particularly in huge forms or portions of large forms.
2. The Component Designer has not yet been completed, but we are actively working on it. However, the use of Components is fully supported, and the Component Tray is compatible with the.NET Framework Designer. It should be noted, however, that not all of the components that were available by default in the Toolbox in the.NET Framework are supported in the OOP Designer. We have chosen not to support in the OOP Designer certain components that are only available through.NET Platform Extensions (see Windows Compatibility Pack). If you still require certain components, you can utilize them directly in.NET code.
3. The OOP Designer does not include the Typed DataSet Designer. The same is true for type editors in the.NET Framework that go straight to the SQL
Query Editor (like the DataSet component editor). Typed DataSets require the Data Source Provider Service, which is not provided by WinForms. While they have improved the support for Object Data Sources and urge Developers to use it in conjunction with more recent ORMs like EFCore, the OOP Designer can only accept typed DataSets on existing forms that have been migrated from.NET Framework applications.
Highlights and noteworthy takeaways
So, while the majority of the fundamental Designer capability is identical to that of the.NET Framework Designer, there are several crucial differences:
They removed the.NET WinForms Designer from the procedure. While Visual Studio 2022 only supports the 64-bit.NET Framework, the new Designer’s server process operates in the bitness of the project and as a.NET process. This, however, comes with a few breaking changes, mostly with the creation of Control Designers.
Object Data Sources are fundamental to data binding. While legacy support for Typed Dataset-based data layers is presently restricted, they encourage adopting contemporary ORMs like EntityFramework or, even better, EFCore for.NET. To create Object Data Sources, use the DesignBindingPicker and the new Databinding Dialog.
The WinForms Designer Extensibility SDK is required by control library writers that want greater Design-Time Support for their controls than custom-type editors. Framework control designers can no longer operate without changing them for the new.NET WinForms Designer’s OOP architecture.
Let us know what subjects you’d want to hear about in relation to the WinForms Designer—the new Object Data Source capability in the OOP Designer and the WinForms Designer SDK are currently in the works and at the top of our list.
Please keep in mind that the WinForms.NET runtime is open source, and you are welcome to contribute! Check out the WinForms GitHub repo if you have any suggestions, have encountered issues, or wish to take on PRs related to the WinForms runtime.