{"id":43042,"date":"2022-11-08T08:58:15","date_gmt":"2022-11-08T15:58:15","guid":{"rendered":"https:\/\/devblogs.microsoft.com\/dotnet\/?p=43042"},"modified":"2024-12-13T14:20:19","modified_gmt":"2024-12-13T22:20:19","slug":"winforms-enhancements-in-dotnet-7","status":"publish","type":"post","link":"https:\/\/devblogs.microsoft.com\/dotnet\/winforms-enhancements-in-dotnet-7\/","title":{"rendered":"What&#8217;s new in Windows Forms in .NET 7.0"},"content":{"rendered":"<p>There are a lot of exciting enhancements for Windows Forms developers in .NET 7. We are committed to support and innovate in the Windows Forms runtime, so let&#8217;s look at what is new in .NET 7.<\/p>\n<h2>Accessibility improvements and fixes<\/h2>\n<p>We strive to improve the experience for users of assistive technology. This release adds further improvements to accessibility, including but not limited to the following:<\/p>\n<ul>\n<li>Many announcement-related issues observed in screen readers (e.g., Narrator) have been addressed, ensuring the information about controls is correct and complete. For example, <code>ListView<\/code> now correctly announces when a group is expanded or collapsed.<\/li>\n<li>More controls now provide UI Automation support:\n<ul>\n<li><code>TreeView<\/code><\/li>\n<li><code>DateTimePicker<\/code><\/li>\n<li><code>ToolStripContainer<\/code> and <code>ToolStripPanel<\/code><\/li>\n<li><code>FlowLayoutPanel<\/code>, <code>TableLayoutPanel<\/code> and <code>SplitContainer<\/code><\/li>\n<li><code>PrintPreviewControl<\/code><\/li>\n<li><code>WebBrowser<\/code><\/li>\n<\/ul>\n<\/li>\n<li>Multiple memory leaks resulting from running Windows Forms applications under assistive tools (e.g., Narrator) have been fixed. Specifically, some controls and their corresponding accessible objects would remain in memory after a form that hosted those controls was closed.<\/li>\n<li>Assistive tools now accurately draw focus indicators and report correct bounding rectangles for nested forms and some elements of composite controls, such as <code>DataGridView<\/code>, <code>ListView<\/code>, <code>TabControl<\/code> and others.<\/li>\n<li><a href=\"https:\/\/learn.microsoft.com\/windows\/win32\/winauto\/uiauto-implementingexpandcollapse\">ExpandCollapse Control Pattern<\/a> support in <code>ListView<\/code>, <code>TreeView<\/code> and <code>PropertyGrid<\/code> controls has been corrected to activate only for expandable items.<\/li>\n<li>Various color contrast ratio corrections in <code>Button<\/code>, <code>DataGridView<\/code> and <code>PropertyGrid<\/code> controls.<\/li>\n<li>Visibility improvements for <code>ToolStripTextBox<\/code> and <code>ToolStripButton<\/code> in high-contrast themes.<\/li>\n<\/ul>\n<p><img decoding=\"async\" src=\"https:\/\/devblogs.microsoft.com\/dotnet\/wp-content\/uploads\/sites\/10\/2022\/11\/accessibility.png\" alt=\"Accessibility improvements\" \/><\/p>\n<h2>High DPI and scaling improvements<\/h2>\n<p>Throughout the .NET 7 release we continued our work on improving the high DPI support in multi-monitor scenarios (that is, <code>PerMonitorV2<\/code>). Most notably, the Windows Forms runtime now can:<\/p>\n<ul>\n<li>Correctly scale nested controls (e.g., a button which resides in panel, which itself is placed on a tabpage). This class of layout issues was caused by the different order of Windows messages \u2013 in <code>PerMonitorV2<\/code> mode, a parent control receive the <a href=\"https:\/\/learn.microsoft.com\/windows\/win32\/hidpi\/wm-dpichanged\"><code>WM_DPICHANGED<\/code><\/a> message <em>after<\/em> all its children have received the message and scaled themselves.<\/li>\n<li>Scale <a href=\"https:\/\/learn.microsoft.com\/dotnet\/api\/system.windows.forms.form.maximumsize\"><code>Form.MaximumSize<\/code><\/a> and <a href=\"https:\/\/learn.microsoft.com\/dotnet\/api\/system.windows.forms.form.minimumsize\"><code>Form.MinimumSize<\/code><\/a> properties based on the current monitor DPI settings for applications that run <a href=\"https:\/\/learn.microsoft.com\/dotnet\/core\/project-sdk\/msbuild-props-desktop#applicationhighdpimode\"><code>ApplicationHighDpiMode<\/code><\/a> set to <code>PerMonitorV2<\/code>.<\/li>\n<\/ul>\n<p>The progress is slow because any changes in the layout engine carry a very high risk. To help reduce the risk we have (re-)introduced &#8220;feature switches&#8221; back into Windows Forms runtime. This will allow us to add new features and functionality with an escape plan, if those don&#8217;t work out for our developers.<\/p>\n<p>In .NET 7 we added the first switch <code>System.Windows.Forms.ScaleTopLevelFormMinMaxSizeForDpi<\/code> that controls whether the form&#8217;s <code>MaximumSize<\/code> and <code>MinimumSize<\/code> properties are scaled whenever <a href=\"https:\/\/learn.microsoft.com\/windows\/win32\/hidpi\/wm-dpichanged\"><code>WM_DPICHANGED<\/code><\/a> message is received.<\/p>\n<p>In .NET 7 the new scaling behaviour is <em>disabled<\/em> by default, but in .NET 8 it will be <em>on by default<\/em>. The switch can be configured via <a href=\"https:\/\/learn.microsoft.com\/dotnet\/core\/runtime-config\/#runtimeconfigjson\">runtimeconfig.json<\/a> like so:<\/p>\n<pre><code class=\"language-json\">{\r\n  \"runtimeOptions\": {\r\n    \"tfm\": \"net7.0\",\r\n    \"frameworks\": [\r\n        ...\r\n    ],\r\n    \"configProperties\": {\r\n      \"System.Windows.Forms.ScaleTopLevelFormMinMaxSizeForDpi\": true,\r\n    }\r\n  }\r\n}<\/code><\/pre>\n<h2>Databinding improvements<\/h2>\n<p>We want to help Windows Forms developers to modernize their existing apps and to adopt new cloud-based technologies. One way to modernize is the ability to move business logic of a typical line-of-business (LOB) application away from the Windows Forms code-behind pattern towards more modern patterns like <a href=\"https:\/\/learn.microsoft.com\/dotnet\/architecture\/maui\/mvvm\">Model-View-ViewModel<\/a> (MVVM), which can be easily reused and tested. We also wanted to provide an incentive to pivot away from the 15-year-old Typed DataSets. They have very limited support in the Windows Forms <a href=\"https:\/\/devblogs.microsoft.com\/dotnet\/state-of-the-windows-forms-designer-for-net-applications\/\">out-of-process designer<\/a> because Visual Studio no longer supports Data Source Provider Service for the .NET runtime. The feedback to the proposed <a href=\"https:\/\/devblogs.microsoft.com\/dotnet\/databinding-with-the-oop-windows-forms-designer\/#new-approaches-when-using-object-data-source-binding\">new Binding strategy<\/a> was very positive and indicated that we&#8217;re on the right track with that.<\/p>\n<p>Windows Forms already had a powerful binding engine, but to achieve the above goals we introduced support for a more modern form of data binding with data contexts and command patterns, similar to data binding provided by WPF.<\/p>\n<p><img decoding=\"async\" src=\"https:\/\/devblogs.microsoft.com\/dotnet\/wp-content\/uploads\/sites\/10\/2022\/11\/databinding.png\" alt=\"Databinding, command binding\" \/><\/p>\n<p>The new API surface is as follows:<\/p>\n<pre><code class=\"language-diff\">     public class Control  {\r\n+        [BindableAttribute(true)]\r\n+        public virtual object DataContext { get; set; }\r\n+        [BrowsableAttribute(true)]\r\n+        public event EventHandler DataContextChanged;\r\n+        protected virtual void OnDataContextChanged(EventArgs e);\r\n+        protected virtual void OnParentDataContextChanged(EventArgs e);\r\n     }\r\n\r\n+    [RequiresPreviewFeaturesAttribute]\r\n+    public abstract class BindableComponent : Component, IBindableComponent, IComponent, IDisposable {\r\n+        protected BindableComponent();\r\n+        public BindingContext? BindingContext { get; set; }\r\n+        public ControlBindingsCollection DataBindings { get; }\r\n+        public event EventHandler BindingContextChanged;\r\n+        protected virtual void OnBindingContextChanged(EventArgs e);\r\n+    }\r\n\r\n     public abstract class ButtonBase : Control {\r\n+        [BindableAttribute(true)]\r\n+        [RequiresPreviewFeaturesAttribute]\r\n+        public ICommand? Command { get; set; }\r\n+        [BindableAttribute(true)]\r\n+        public object? CommandParameter { [RequiresPreviewFeaturesAttribute] get; [RequiresPreviewFeaturesAttribute] set; }\r\n+        [RequiresPreviewFeaturesAttribute]\r\n+        public event EventHandler? CommandCanExecuteChanged;\r\n+        [RequiresPreviewFeaturesAttribute]\r\n+        public event EventHandler? CommandChanged;\r\n+        [RequiresPreviewFeaturesAttribute]\r\n+        public event EventHandler? CommandParameterChanged;\r\n+        [RequiresPreviewFeaturesAttribute]\r\n+        protected virtual void OnCommandCanExecuteChanged(EventArgs e);\r\n+        [RequiresPreviewFeaturesAttribute]\r\n+        protected virtual void OnCommandChanged(EventArgs e);\r\n+        [RequiresPreviewFeaturesAttribute]\r\n+        protected virtual void OnCommandParameterChanged(EventArgs e);\r\n+        [RequiresPreviewFeaturesAttribute]\r\n+        protected virtual void OnRequestCommandExecute(EventArgs e);\r\n     }\r\n\r\n+    public abstract class ToolStripItem : BindableComponent, IComponent, IDisposable, IDropTarget {\r\n+        [BindableAttribute(true)]\r\n+        [RequiresPreviewFeaturesAttribute]\r\n+        public ICommand Command { get; set; }\r\n+        [BindableAttribute(true)]\r\n+        public object CommandParameter { [RequiresPreviewFeaturesAttribute] get; [RequiresPreviewFeaturesAttribute] set; }\r\n+        [RequiresPreviewFeaturesAttribute]\r\n+        public event EventHandler CommandCanExecuteChanged;\r\n+        [RequiresPreviewFeaturesAttribute]\r\n+        public event EventHandler CommandChanged;\r\n+        [RequiresPreviewFeaturesAttribute]\r\n+        public event EventHandler CommandParameterChanged;\r\n+        [RequiresPreviewFeaturesAttribute]\r\n+        protected virtual void OnCommandCanExecuteChanged(EventArgs e);\r\n+        [RequiresPreviewFeaturesAttribute]\r\n+        protected virtual void OnCommandChanged(EventArgs e);\r\n+        [RequiresPreviewFeaturesAttribute]\r\n+        protected virtual void OnCommandParameterChanged(EventArgs e);\r\n+        [RequiresPreviewFeaturesAttribute]\r\n+        protected virtual void OnRequestCommandExecute(EventArgs e);\r\n     }<\/code><\/pre>\n<p>The new data binding features allows you to fully embrace the MVVM pattern and the use of object-relational mappers from ViewModels in Windows Forms much easier than before. This, in turn, makes it possible to reduce code in the code-behind files, and opens new testing possibilities. More importantly, it enables code share between Windows Forms and other .NET GUI frameworks such as WPF, UWP\/WinUI and MAUI. (To preempt any questions, there are no plans to introduce support for XAML into Windows Forms.)<\/p>\n<p>It&#8217;s important to add that these new binding features are only available under <a href=\"https:\/\/learn.microsoft.com\/dotnet\/core\/project-sdk\/msbuild-props#enablepreviewfeatures\">&#8220;preview&#8221; status<\/a> in .NET 7, so that we can react to developer feedback and tweak the binding during the .NET 8 development cycle. We expect that the new binding functionality will become generally available in .NET 8.<\/p>\n<p>To enable the new binding, you need to add <code>&lt;EnablePreviewFeatures&gt;true&lt;\/EnablePreviewFeatures&gt;<\/code> to your project file. This is supported for both C# <em>and<\/em> Visual Basic from the start.<\/p>\n<h2>ComWrappers and native AOT<\/h2>\n<p>In .NET 7 as part of a wider experiment we replaced the selected Windows Forms built-in COM interops with <a href=\"https:\/\/learn.microsoft.com\/dotnet\/standard\/native-interop\/cominterop\">ComWrappers<\/a>.<\/p>\n<p>&#8211; <em>What&#8217;s the difference?<\/em> &#8211; you may ask. Mostly it&#8217;s that the built-in COM gets completely disabled in trimming\/native AOT scenarios. That was one of the reasons why trimming was disabled for Windows Forms in .NET 5.<\/p>\n<p>&#8211; <em>Why does this matter for Windows Forms which disables trimming during <code>dotnet publish<\/code> step?<\/em> &#8211; you may ask again. Even if trimming is disabled it still works, and the migration work allows for further experiments. As an example, it greatly simplifies the ability to run code in <a href=\"https:\/\/learn.microsoft.com\/dotnet\/core\/deploying\/native-aot\/\">native AOT<\/a> without additional customizations. In addition, if you provide a global ComWrappers implementation for the missing accessibility COM objects, you could run a Windows Forms application under native AOT.<\/p>\n<p>:warning: This work is still highly experimental, and some scenarios are rough and require manual work. Mostly this comes from the <a href=\"https:\/\/learn.microsoft.com\/dotnet\/core\/deploying\/native-aot\/#limitations-of-native-aot-deployment\">native AOT limitations<\/a> and <a href=\"https:\/\/learn.microsoft.com\/dotnet\/core\/deploying\/trimming\/fixing-warnings\">trimming quirks<\/a>. Please keep in mind that you need to test your application after you publish.<\/p>\n<p>If you feel adventurous and wish to experiment or just like to know more about ComWrappers and native AOT for Windows Forms, see <a href=\"https:\/\/github.com\/kant2002\">@kant2002<\/a>&#8216;s post on Medium <a href=\"https:\/\/codevision.medium.com\/again-winforms-and-nativeaot-fd068425cc13\">&#8220;Again WinForms and NativeAOT&#8221;<\/a> and his <a href=\"https:\/\/github.com\/kant2002\/winformscominterop\">GitHub repository<\/a>.<\/p>\n<h2>Other notable changes<\/h2>\n<p>In no particular order:<\/p>\n<ul>\n<li><a href=\"https:\/\/github.com\/dotnet\/winforms\/pull\/6576\">dotnet\/winforms#6576<\/a> enhanced drag-and-drop handling to match the Windows drag-and-drop functionality with richer display effects with an icon and a text label.\n<p><img decoding=\"async\" src=\"https:\/\/devblogs.microsoft.com\/dotnet\/wp-content\/uploads\/sites\/10\/2022\/11\/dragndrop.png\" alt=\"Drag-and-drop ehancement\" \/><\/li>\n<li><a href=\"https:\/\/github.com\/dotnet\/winforms\/pull\/6244\">dotnet\/winforms#6244<\/a> brought the file and folder dialogs options to parity with the <a href=\"https:\/\/learn.microsoft.com\/windows\/win32\/api\/shobjidl_core\/ne-shobjidl_core-_fileopendialogoptions\">options available in Windows dialogs<\/a>, such as don&#8217;t add to recent, ok button needs interaction, force show hidden, and more.<\/li>\n<li><a href=\"https:\/\/github.com\/dotnet\/winforms\/pull\/7403\">dotnet\/winforms#7403<\/a> made <code>TreeView<\/code> control respect the <code>DoubleBuffer<\/code> property.<\/li>\n<li><a href=\"https:\/\/github.com\/dotnet\/winforms\/pull\/6234\">dotnet\/winforms#6234<\/a> extended <code>ErrorProvider<\/code> with <code>HasErrors<\/code> property.<\/li>\n<li><a href=\"https:\/\/github.com\/dotnet\/winforms\/pull\/6335\">dotnet\/winforms#6335<\/a> fixed the <code>Form<\/code>&#8216;s snap layout in Windows 11.<\/li>\n<\/ul>\n<p>And we have some very cool new <a href=\"https:\/\/github.com\/dotnet\/winforms\/tree\/main\/src\/System.Windows.Forms\/tests\/IntegrationTests\/UIIntegrationTests\">UI integration tests<\/a> as a direct result of some of these changes.<\/p>\n<h2>Breaking Changes<\/h2>\n<p>While we intend to maintain backward compatibility with .NET Framework and previous .NET releases as much as possible, it is not always prudent. Follow the link to see the <a href=\"https:\/\/learn.microsoft.com\/dotnet\/core\/compatibility\/7.0#windows-forms\">list of breaking changes<\/a>.<\/p>\n<h2>Community contributions<\/h2>\n<p>The community continues to play an important part in the life of Windows Forms runtime and the SDK. In .NET 7 timeframe we have merged over 700 pull requests (excluding the automated pull requests) in <a href=\"https:\/\/github.com\/dotnet\/winforms\/\">dotnet\/winforms<\/a> repository with almost 60% of those pull requests authored by the community. All these contributions \u2013 big and small \u2013 are really appreciated.<\/p>\n<p>We&#8217;d like to call out a few community contributors:<\/p>\n<ul>\n<li><a href=\"https:\/\/github.com\/gpetrou\">@gpetrou<\/a> has been tirelessly helping with nullable reference types annotations. This work isn&#8217;t over, but as you can see from the <a href=\"https:\/\/github.com\/dotnet\/core\/tree\/main\/release-notes\/7.0\/preview\/api-diff\">API diff<\/a> the progress is substantial.<\/li>\n<li><a href=\"https:\/\/github.com\/kant2002\">@kant2002<\/a> has been driving the ComWrappers and Windows Forms native AOT stories.<\/li>\n<li><a href=\"https:\/\/github.com\/willibrandon\">@willibrandon<\/a> has helped modernizing the drag and drop and the dialogs functionality, as well as writing very elaborate tests for the drag and drop scenarios.<\/li>\n<li><a href=\"https:\/\/github.com\/kirsan31\">@kirsan31<\/a> has taken interest in perf-related issues and removed redundant finalizers, as well as helped stabilizing flaky tests.<\/li>\n<li><a href=\"https:\/\/github.com\/jbhensley\">@jbhensley<\/a> spent some time fixing various control rendering issues (some of which date back to .NET Framework).<\/li>\n<\/ul>\n<h2>Looking ahead<\/h2>\n<p>We are committed to providing the complete support for <code>PerMonitorV2<\/code> mode. We will continue to work on the scaling-related issues (e.g., <a href=\"https:\/\/github.com\/dotnet\/winforms\/pull\/7973\">dotnet\/winforms#7973<\/a>). We&#8217;re also working on a new layout and anchor calculation mechanisms, which are not only expected to address the anchoring issues but should also deliver performance improvements. You can learn more about the new achor layout at <a href=\"https:\/\/github.com\/dotnet\/winforms\/pull\/7956\">dotnet\/winforms#7956<\/a>. In addition, we&#8217;ve been considering how we can improve the designer-related developer experience in this area.<\/p>\n<p>We are also set to continue our modernization journey and to closer align our functionality with Windows. We have started replacing our manually created interop code with the source-generated interops produced by <a href=\"https:\/\/github.com\/microsoft\/CsWin32\">CsWin32 project<\/a>. This not only reduces the maintenance burden for the team, but also opens up new possibilities (e.g., <a href=\"https:\/\/github.com\/dotnet\/winforms\/issues\/7641\">support Windows 11 dark mode<\/a>). We also expect that it may help advancing the trimming and the native AOT stories.<\/p>\n<p>Furthermore, we will continue our work to migrate built-in COM to ComWrapper and bypass the .NET COM interop layer, where possible. And, hopefully, next time around, we will have a significantly better story for self-contained, single-file Windows Forms applications.<\/p>\n<h2>Reporting bugs and suggesting features<\/h2>\n<p>If you have any comments, suggestions or faced some issues, please let us know! Submit Visual Studio and Designer related issues via <strong>Visual Studio Feedback<\/strong> (look for a button in the top right corner in Visual Studio), and Windows Forms runtime related issues at <a href=\"https:\/\/github.com\/dotnet\/winforms\">dotnet\/winforms<\/a> repository.<\/p>\n<p>We also consider API proposals that further enrich Windows Forms SDK and make it easier to build Windows applications. And if you champion a proposal &#8211; there is a high chance that you will see it in the Windows Forms SDK.<\/p>\n<p>You can also become a contributor to the Windows Forms code base! Our repository has items marked <a href=\"https:\/\/github.com\/dotnet\/winforms\/labels\/help%20wanted\">&#8220;help wanted&#8221;<\/a> and <a href=\"https:\/\/github.com\/dotnet\/winforms\/labels\/api-approved\">API approved for implementation<\/a>, we would really appreciate your help implementing them!<\/p>\n<p>Happy coding!<\/p>\n","protected":false},"excerpt":{"rendered":"<p>Read about the new features that are in Windows Forms in .NET 7 including new accessibility features, High DPI, UI Automation, and more.<\/p>\n","protected":false},"author":13586,"featured_media":43251,"comment_status":"open","ping_status":"closed","sticky":false,"template":"","format":"standard","meta":{"_acf_changed":false,"footnotes":""},"categories":[685,7163],"tags":[7611,7342,7221,319],"class_list":["post-43042","post","type-post","status-publish","format-standard","has-post-thumbnail","hentry","category-dotnet","category-winforms","tag-dotnet-7","tag-designer","tag-windows-forms","tag-winforms"],"acf":[],"blog_post_summary":"<p>Read about the new features that are in Windows Forms in .NET 7 including new accessibility features, High DPI, UI Automation, and more.<\/p>\n","_links":{"self":[{"href":"https:\/\/devblogs.microsoft.com\/dotnet\/wp-json\/wp\/v2\/posts\/43042","targetHints":{"allow":["GET"]}}],"collection":[{"href":"https:\/\/devblogs.microsoft.com\/dotnet\/wp-json\/wp\/v2\/posts"}],"about":[{"href":"https:\/\/devblogs.microsoft.com\/dotnet\/wp-json\/wp\/v2\/types\/post"}],"author":[{"embeddable":true,"href":"https:\/\/devblogs.microsoft.com\/dotnet\/wp-json\/wp\/v2\/users\/13586"}],"replies":[{"embeddable":true,"href":"https:\/\/devblogs.microsoft.com\/dotnet\/wp-json\/wp\/v2\/comments?post=43042"}],"version-history":[{"count":0,"href":"https:\/\/devblogs.microsoft.com\/dotnet\/wp-json\/wp\/v2\/posts\/43042\/revisions"}],"wp:featuredmedia":[{"embeddable":true,"href":"https:\/\/devblogs.microsoft.com\/dotnet\/wp-json\/wp\/v2\/media\/43251"}],"wp:attachment":[{"href":"https:\/\/devblogs.microsoft.com\/dotnet\/wp-json\/wp\/v2\/media?parent=43042"}],"wp:term":[{"taxonomy":"category","embeddable":true,"href":"https:\/\/devblogs.microsoft.com\/dotnet\/wp-json\/wp\/v2\/categories?post=43042"},{"taxonomy":"post_tag","embeddable":true,"href":"https:\/\/devblogs.microsoft.com\/dotnet\/wp-json\/wp\/v2\/tags?post=43042"}],"curies":[{"name":"wp","href":"https:\/\/api.w.org\/{rel}","templated":true}]}}