{"id":44066,"date":"2023-01-25T10:15:00","date_gmt":"2023-01-25T18:15:00","guid":{"rendered":"https:\/\/devblogs.microsoft.com\/dotnet\/?p=44066"},"modified":"2023-01-31T11:26:08","modified_gmt":"2023-01-31T19:26:08","slug":"winforms-cross-platform-dotnet-maui-command-binding","status":"publish","type":"post","link":"https:\/\/devblogs.microsoft.com\/dotnet\/winforms-cross-platform-dotnet-maui-command-binding\/","title":{"rendered":"Using Command Binding in Windows Forms apps to go Cross-Platform"},"content":{"rendered":"<p>Large line-of-business WinForms applications can often benefit from the use of\nthe Model-View-ViewModel (MVVM) pattern to simplify maintenance, reuse, and unit\ntesting. In this post, I&#8217;ll explain the important concepts and architectural\npatterns of MVVM including data binding and command binding. Then we will take a look at how you can leverage modern libraries, .NET 7 features,\nand Visual Studio tooling to efficiently modernize your WinForms applications. By the end, you will see how this approach sets your application up to go cross-platform with popular frameworks like .NET MAUI which can leverage the MVVM code across iOS, Android, Mac, and Windows.<\/p>\n<h2>Say Goodbye to Code-behind: WinForms meets MVVM &amp; .NET MAUI<\/h2>\n<p>One of the features that has led WinForms to its overwhelming popularity as a\nRAD (rapid application development) tool is often, for large line-of-business\napps, also its biggest architectural challenge: placing application logic as\ncode behind UI-Element&#8217;s event handlers. As an example: The developer wants to\ndisplay a database view after a mouse click on a pulldown menu entry. The\npulldown menu is located in the main form of the application. This form is a\nclass derived from <code>System.Windows.Forms<\/code>, so it has dependencies to the .NET\nWinForms runtime. This means every line of code put here can only be reused in\na context of <em>a<\/em>, probably even only if the context of exactly <em>this<\/em> WinForms\napp. Typically for WinForms, user interaction with any UI elements triggers\nevents. These events are then handled in corresponding event handler routines,\nand this approach is often called <em>code-behind<\/em>. So, the <em>code behind<\/em> the menu\nentry is triggered. In many cases, the form is now executing the logic for a\ndomain-specific task that basically has nothing to do with the UI. For large\nline-of-business apps, this can quickly become an architectural nightmare.<\/p>\n<p>In the case of this example, the code which is executed as a result of a user\nclicking a menu item contains many steps. The form connects to a database, sends\na query to that database, then feeds the data, perhaps prepares it by performing\nadditional calculations or pulling in additional data from other sources, and\nfinally passes the resulting data set to another WinForms form which it then\npresents in a <code>DataGridView<\/code>. Code-behind application architectures in this way\ntend to easily mix domain-specific with UI-technical tasks. The resulting\ncodebase is not only difficult to maintain, it is also hard to reuse in other\nscenarios, let alone easily support unit testing of the business logic.<\/p>\n<h2>Enter UI-Controller architecture<\/h2>\n<p>With the introduction of Windows Presentation Foundation (WPF) in 2008, a new\ndesign pattern emerged that set out to clean up the code-behind spaghetti\narchitecture of previous UI stacks and introduced a clear separation of code\nbased on the layer in the application: UI-relevant code remained alone in a view\nlayer, domain-specific code migrated to a ViewModel layer, and additional data\ntransport classes, which were used to transport data from a database or an alike\ndata source and were processed in the view model, were simply called <em>Model<\/em>\nclasses.<\/p>\n<p>The name of the pattern became <em>Model-View-ViewModel<\/em>, or <em>MVVM<\/em> for short. The\nprocessing of data and the execution of the domain-specific code are reserved\nfor the ViewModel. As an example, the business logic for an accounting\napplication only runs in the context of one (or more) ViewModel assemblies.\nProjects that build these assemblies have no references to concrete UI stacks\nlike WinForms, WPF or .NET MAUI. Rather, they provide an invisible or virtual UI\nonly through properties, which are then linked to the UI at runtime via data\nbinding.<\/p>\n<p>This technique is not entirely new for WinForms apps. Abstraction via\ndata binding was already common practice in the VB6 days and became even more\nflexible with WinForms and the introduction of Typed DataSets. The abstraction\nof data and UI worked according to the same principle then as it does today: The\nvarious properties of a data source (in MVVM the ViewModel, in typical WinForms\nor VB6 architectures often a filtered and specially prepared view of the\ndatabase directly) are bound to specific control elements of the UI. The\n<code>Firstname<\/code> property of a data source class is bound to the <code>Text<\/code> property of\nthe <code>FirstnameTextBox<\/code> control. The <code>JoinDate<\/code> property of the same data source\nclass is bound to the <code>Value<\/code> property of the <code>JoinDateTimePicker<\/code> control, and\nso on. Even the notifications of the data classes to the UI that data has\nchanged worked in the first WinForms versions in the same way as is still the\ncase today in WPF, WinUI or .NET MAUI: data classes implement an interface\ncalled <code>INotifyPropertyChanged<\/code>. This mandates an event called <code>PropertyChanged<\/code>\nfor the data source classes. It is then the task of the data classes to\ndetermine in the respective setters of the property implementations whether the\nproperty value had really changed and, if this is the case, to trigger the\ncorresponding event, specifying the property name. A typical implementation of a\nproperty in a class looks something like this:<\/p>\n<pre><code class=\"language-cs\">    public class NotifyPropertyChangeDemo : INotifyPropertyChanged\n    {\n        \/\/ The event that is fired when a property changes.\n        public event PropertyChangedEventHandler? PropertyChanged;\n\n        \/\/ Backing field for the property.\n        private string? _lastName;\n        private string? _firstName;\n\n        \/\/ The property that is being monitored.\n        public string? LastName\n        {\n            get =&gt; _lastName;\n\n            set\n            {\n                if (_lastName == value)\n                {\n                    return;\n                }\n\n                _lastName = value;\n\n                \/\/ Notify the UI that the property has changed.\n                \/\/ Using CallerMemberName at the call site will automatically fill in\n                \/\/ the name of the property that changed.\n                OnPropertyChanged();\n            }\n        }\n\n        public string? FirstName\n        {\n            get =&gt; _firstName;\n\n            set\n            {\n                if (_firstName == value)\n                {\n                    return;\n                }\n\n                _firstName = value;\n                OnPropertyChanged();\n            }\n        }\n\n        private void OnPropertyChanged([CallerMemberName] string propertyName = \"\") \n            =&gt; PropertyChanged?.Invoke(this, new PropertyChangedEventArgs(propertyName));\n    }<\/code><\/pre>\n<p>In summary, the general idea is to remote-control the actual UI through data\nbinding. However, in contrast to the original thought coming from VB6 and the\nclassical WinForms data binding, using a UI-Controller pattern like MVVM is more\nthan a convenience to populate a complex form with data: While VB6 and classic\nWinForms applications typically only used populated data classes like Typed\nDataSets or Entity Framework model class instances, the ViewModel holds the data\n<em>and<\/em> encapsulates the business logic to prepare that data logically in such a\nway that practically the only task of the UI layer is to present the data in a\nuser-friendly way.<\/p>\n<h3>UI-Controller Architecture in WinForms: To what end?<\/h3>\n<p>If you wanted to architect and develop a new application from scratch, you would\nmost likely consider using a modern UI stack for your new development endeavors,\nand in many cases, that makes sense. If you were to start developing a new\nWindows app from scratch, a more modern stack like\n<a href=\"https:\/\/learn.microsoft.com\/windows\/apps\/winui\/winui3\/create-your-first-winui3-app\">WinUI<\/a>\nmight be a meaningful alternative. Alternatively, a web-based front end and\nadapting technologies like\n<a href=\"https:\/\/learn.microsoft.com\/aspnet\/core\/blazor\/?view=aspnetcore-7.0\">Blazor<\/a> or\n<a href=\"https:\/\/angular.io\/start#:~:text=In%20the%20product-list%20folder%2C%20open%20the%20template%20file,as%20in%20the%20%28click%29%20event%20on%20the%20\">Angular\/TypeScript<\/a>\nalso have merit. But it&#8217;s often not that easy in real life. Here is a list of\npoints to consider, why adapting a UI-Controller architecture for new or\nexisting WinForms apps makes sense:<\/p>\n<ul>\n<li>\n<p><strong>Acceptance of UI paradigm changes in LOB apps:<\/strong> Users usually are trained\nnot only in one particular business application, but also build muscle memory\nin how the UI is handled across an LOB app-suite in general. If LOB apps get\nrewritten for a new UI Stack, additional training for the users needs to be\ntaken into account. Modernizing the core of a WinForms business app without\nchanging the workflow for a big existing user base might be a requirement in\ncertain scenarios.<\/p>\n<\/li>\n<li>\n<p><strong>Feasibility of re-writes of huge line-of-business apps:<\/strong> There are hundreds\nof thousands of line-of-business WinForms apps already out there. Simply\ndiscarding a huge, often several hundred-thousand lines of code business app\nis simply not feasible. It makes more sense to re-architect and modernize such\nan app step by step. The vast majority of development teams simply don&#8217;t have\nthe time to keep supporting the actively in-use legacy app while developing\nthe same app &#8211; modernized, based on a completely new technology &#8211; from\nscratch. Modernizing the app in place, step-by-step, and area by area is often\nthe only viable alternative.<\/p>\n<\/li>\n<li>\n<p><strong>Unit tests for ViewModels:<\/strong> Introducing a UI-controller architecture into\nan existing LOB app opens up another advantage: Since\nUI-Controllers\/ViewModels are not supposed to have dependencies to certain UI\ntechnologies, unit tests for such apps can be implemented much more easily. We\ncover this topic in more detail in the context of the sample app below.<\/p>\n<\/li>\n<li>\n<p><strong>Mobile Apps spin-offs:<\/strong> The necessity for spin-offs of mobile apps from a\nlarge WinForms line-of-business apps is a growing requirement for many\nbusinesses. With an architecture in which ViewModels can be shared and\ncombined between for example WinForms and .NET MAUI, the development of such\nmobile apps can be streamlined with a lot of synergy effects. This topic is\nalso covered in more detail in the context of the sample app.<\/p>\n<\/li>\n<li>\n<p><strong>Consolidating and modernizing backend technologies:<\/strong> Last but not at all\nleast &#8211; with a proper architecture &#8211; consolidating onsite server-backends and\nmigrating the backends of a LOB apps to Azure based cloud technologies is\nstraight forward, and can be done as a migration project over time. The users\ndo not lose their usual way of working and the modernization can happen mostly\nin the background without interruptions.<\/p>\n<\/li>\n<\/ul>\n<h3>The sample apps of this blog post<\/h3>\n<p>You can find the sample app used in this blog post <a href=\"https:\/\/github.com\/microsoft\/winforms-designer-extensibility\/tree\/main\/Samples\/CommandBinding\">in the WinForms-Designer-Extensibility Github\nrepo<\/a>. It contains\nthese areas:<\/p>\n<ul>\n<li>The simplified scenarios used in this blog post to explain the\nUI-Controller\/MVVM approach in WinForms with the new WinForms Command Binding\nfeatures. You find this samples in the project <em>MauiEdit.ViewModel<\/em> in the solution folder <em>Examples<\/em>.<\/li>\n<li>A bigger example (the WinForms Editor), showing the new WinForms features in\nthe context of a real-world scenario.<\/li>\n<li>A .NET MAUI-Project, adapting the exact same ViewModel used for the WinForms\nApp for a .NET MAUI app. We are limiting the showcase here to Android for\nsimplicity in this context.<\/li>\n<li>\n<p>A unit test project, which shows how using ViewModels enables you to write\nunit tests for a UI based on an UI-Controller abstraction like MVVM.<\/p>\n<p><img decoding=\"async\" src=\"https:\/\/devblogs.microsoft.com\/dotnet\/wp-content\/uploads\/sites\/10\/2023\/01\/SampleAppSolution.png\" alt=\"Screenshot of the sample app in the solution explorer showing the 4 projects .NET MAUI, WinForms, UnitTest and ViewModel.\" \/><\/p>\n<\/li>\n<\/ul>\n<p><strong>NOTE:<\/strong> This blog post is not an introduction to .NET MAUI. There are a lot of\nresources on the web, showing the basic approach of MVVM with XAML-based UI\nstacks, an <a href=\"https:\/\/learn.microsoft.com\/dotnet\/architecture\/maui\/introduction\">Introduction to .NET MAUI<\/a>, many examples, and lots of <a href=\"https:\/\/www.youtube.com\/watch?v=DuNLR_NJv8U\">really good YouTube videos<\/a>.<\/p>\n<p><img decoding=\"async\" src=\"https:\/\/devblogs.microsoft.com\/dotnet\/wp-content\/uploads\/sites\/10\/2023\/01\/MauiWinFormsEditor.gif\" alt=\"Animated gif which shows the WinForms and the Android version of the sample editor in action.\" \/><\/p>\n<h2>Command Binding for calling methods inside the UI-controller<\/h2>\n<p>While WinForms brought a pretty complete infrastructure for data binding along\nfrom the beginning, and data could also flow between the UI and the binding\nsource in both directions, one aspect was missing. Up to now, there wasn&#8217;t a\n&#8220;bindable&#8221; way to connect business logic methods in the data source &#8211; or more\naccurately: the UI-Controller or ViewModel &#8211; with the UI. The goal with the\n<em>separation of concerns<\/em> is that a form or UserControl shouldn&#8217;t execute code\nwhich manipulates business data. It should leave that task completely to that UI\nController. Now, in the spirit of MVVM, the approach is to connect an element of\nthe UI to the a method inside UI-Controller, so when the UI Element is engaged\nin the UI, the respective method in the Controller (the ViewModel) is executed.\nThese methods, which are responsible for the domain-specific functionality\ninside a ViewModel, are called <em>Commands<\/em>. For linking these ViewModel commands\nwith the user interface, MVVM utilizes <em>Command Binding<\/em> which is based on types\nimplementing the\n<a href=\"https:\/\/learn.microsoft.com\/dotnet\/api\/system.windows.input.icommand?view=net-7.0\"><code>ICommand<\/code><\/a>\ninterface. Those types can then be used in UI Controllers like ViewModels to\ndefine properties so they don&#8217;t hold the actual code to be executed, they rather\n<em>point<\/em> to the methods which get automatically executed when the UI Element the\nCommand is bound to in the View gets engaged.<\/p>\n<p><strong>Note:<\/strong> Although <code>ICommand<\/code> is located in the Namespace <code>System.Windows.Input<\/code>\nwhich in principle points to namespaces used in the WPF context, <code>ICommand<\/code>\ndoesn&#8217;t have any dependencies to any existing UI Stack in .NET or the .NET\nFramework. Rather, <code>ICommand<\/code> is used across all .NET based UI Stacks, including\nWPF, .NET MAUI, WinUI, UWP, and now also WinForms.<\/p>\n<p>If you have a Command defined in your ViewModel, you also need <code>Command<\/code>\nproperties in UI elements to bind against. To make this possible for the .NET 7\nWinForms runtime, we made several changes to WinForms controls and components:<\/p>\n<ul>\n<li><strong>Introduced <code>Command<\/code> for <code>ButtonBase<\/code>:<\/strong> <code>ButtonBase<\/code> got a <a href=\"https:\/\/learn.microsoft.com\/dotnet\/api\/system.windows.forms.buttonbase.command?view=windowsdesktop-7.0\"><code>Command<\/code>\nproperty<\/a>\nof type <code>ICommand<\/code>. That means that the controls <code>Button<\/code>, <code>CheckBox<\/code> and\n<code>RadioButton<\/code> in WinForms also now have a <code>Command<\/code> property as will every\nWinForms control derived either from <code>Button<\/code> or <code>ButtonBase<\/code>.<\/li>\n<li><strong>Introduced <code>BindableComponent<\/code>:<\/strong> The WinForms .NET 7 runtime introduced\n<a href=\"https:\/\/learn.microsoft.com\/dotnet\/api\/system.windows.forms.bindablecomponent?view=windowsdesktop-7.0\"><code>BindableComponent<\/code><\/a>.\nBefore, components were not intrinsically bindable in WinForms, they were\nmissing the necessary binding infrastructure. <code>BindableComponent<\/code> derives from\n<code>Component<\/code> and provides the infrastructure to create properties for a\ncomponent, which can be bound.<\/li>\n<li><strong>Made <code>ToolStripItem<\/code> bindable:<\/strong> <a href=\"https:\/\/learn.microsoft.com\/dotnet\/api\/system.windows.forms.toolstripitem?view=windowsdesktop-7.0\"><code>ToolStripItem<\/code><\/a> no longer derives from\n<code>Component<\/code> but rather now from <code>BindableComponent<\/code>. This was necessary, since\n<code>ToolStripButton<\/code> and <code>ToolStripMenuItem<\/code> are desired candidates for command\nbinding targets, but for that they need to be able to be bound to begin with.<\/li>\n<li><strong>Introduced <code>Command<\/code> for <code>ToolStripItem<\/code>:<\/strong> <code>ToolStripItem<\/code> also got a\n<a href=\"https:\/\/learn.microsoft.com\/dotnet\/api\/system.windows.forms.toolstripitem.command?view=windowsdesktop-7.0#system-windows-forms-toolstripitem-command\"><code>Command<\/code><\/a> property of type <code>ICommand<\/code>. Although every component derived from\n<code>ToolStripItem<\/code> now has a <code>Command<\/code> property, especially <code>ToolStripButton<\/code>,\n<code>ToolStripDropDownButton<\/code>, <code>ToolStripMenuItem<\/code> and <code>ToolStripSplitButton<\/code> are\nideal candidates for command binding due to their UI characteristics.<\/li>\n<li><strong>Introduced <code>CommandParameter<\/code> properties:<\/strong> For a simplified passing of\n<code>Command<\/code> parameters, both <code>ButtonBase<\/code> and <code>ToolStripItem<\/code> got a\n<a href=\"https:\/\/learn.microsoft.com\/dotnet\/api\/system.windows.controls.primitives.buttonbase.commandparameter?view=windowsdesktop-7.0\"><code>CommandParameter<\/code>\nproperty<\/a>.\nWhen a command gets executed, the content of <code>CommandParameter<\/code> is\nautomatically passed to the command&#8217;s method in the UI-Controller\/ViewModel.<\/li>\n<li><strong>Introduced public events for new properties:<\/strong> Both <code>ButtonBased<\/code> and\n<code>ToolStripItem<\/code> got the new events\n<a href=\"https:\/\/learn.microsoft.com\/dotnet\/api\/system.windows.forms.buttonbase.commandcanexecutechanged?view=windowsdesktop-7.0\"><code>CommandCanExecuteChanged<\/code><\/a>,\n<a href=\"https:\/\/learn.microsoft.com\/dotnet\/api\/system.windows.forms.buttonbase.commandchanged?view=windowsdesktop-7.0\"><code>CommandChanged<\/code><\/a>\nand\n<a href=\"https:\/\/learn.microsoft.com\/dotnet\/api\/system.windows.forms.buttonbase.commandparameterchanged?view=windowsdesktop-7.0\"><code>CommandParameterChanged<\/code><\/a>.\nWith these events the new properties are supported by the binding\ninfrastructure of WinForms and make the those properties bindable.<\/li>\n<li><strong>Introduced (protected) <code>OnRequestCommandExecute<\/code>:<\/strong> Overriding\n<a href=\"https:\/\/learn.microsoft.com\/dotnet\/api\/system.windows.forms.buttonbase.onrequestcommandexecute?view=windowsdesktop-7.0\"><code>OnRequestCommandExecute<\/code><\/a>\nallows <code>ButtonBase<\/code>&#8211; or <code>ToolStripItem<\/code>-derived classes to intercept the\nrequest to execute a command when the user has clicked a bound command control\nor component. The derived control can then decide <em>not<\/em> to invoke the bound UI\nController&#8217;s or ViewModel&#8217;s command by simply not calling the base class&#8217;s\nmethod.<\/li>\n<\/ul>\n<h3>Controlling Command Execution and Command Availability by Utilizing Relay Commands<\/h3>\n<p>Since <code>ICommand<\/code> is just an interface which mandates properties and methods, a\nUI-Controller or ViewModel needs to use a concrete class instance, which\nimplements the <code>ICommand<\/code> interface.<\/p>\n<p>The <code>ICommand<\/code> interface has three methods:<\/p>\n<ul>\n<li><code>Execute<\/code>: This method is called when the command is invoked. It contain the\ndomain specific the logic.<\/li>\n<li><code>CanExecute<\/code>: This method is called whenever the command&#8217;s context to execute\nchanges. It returns a boolean value indicating the command&#8217;s availability.<\/li>\n<li>\n<p><code>CanExecuteChanged<\/code>: This event is raised whenever the value of the CanExecute method changes.<\/p>\n<p>One typical implementation of a class implementing <code>ICommand<\/code> is called\n<code>RelayCommand<\/code>, and a simplified version would look like this:<\/p>\n<\/li>\n<\/ul>\n<pre><code class=\"language-cs\">    \/\/ Implementation of ICommand - simplified version not taking parameters into account.\n    public class RelayCommand : ICommand\n    {\n        public event EventHandler? CanExecuteChanged;\n\n        private readonly Action _commandAction;\n        private readonly Func&lt;bool&gt;? _canExecuteCommandAction;\n\n        public RelayCommand(Action commandAction, Func&lt;bool&gt;? canExecuteCommandAction = null)\n        {\n            ArgumentNullException.ThrowIfNull(commandAction, nameof(commandAction));\n\n            _commandAction = commandAction;\n            _canExecuteCommandAction = canExecuteCommandAction;\n        }\n\n        \/\/ Implicit interface implementations, since there will never be the necessity to call this \n        \/\/ method directly. It will always exclusively be called by the bound command control.\n        bool ICommand.CanExecute(object? parameter)\n            =&gt; _canExecuteCommandAction is null || _canExecuteCommandAction.Invoke();\n\n        void ICommand.Execute(object? parameter)\n            =&gt; _commandAction.Invoke();\n\n        \/\/\/ &lt;summary&gt;\n        \/\/\/  Triggers sending a notification, that the command availability has changed.\n        \/\/\/ &lt;\/summary&gt;\n        public void NotifyCanExecuteChanged()\n            =&gt; CanExecuteChanged?.Invoke(this, EventArgs.Empty);\n    }<\/code><\/pre>\n<p>When you bind the <code>Command<\/code> property of a control against a property of type\n<code>RelayCommand<\/code> (or any other implementation of <code>ICommand<\/code>), two things happen:<\/p>\n<ul>\n<li>Whenever the user engages the control (by clicking or pressing the related\nshortcut key on the keyboard), the <code>Action<\/code> defined for the RelayCommand gets\nexecuted.<\/li>\n<li>The control whose <code>Command<\/code> property is bound gets disabled when the execution\ncontext changes. The execution context is controlled by the <code>CanExecute<\/code> method\nof the RelayCommand. When it returns <code>false<\/code>, it indicates that the command\ncannot be executed. In that case, the control gets automatically disabled.\nWhen it returns <code>true<\/code>, the opposite happens: the control gets enabled.<\/li>\n<\/ul>\n<p><strong>Note:<\/strong> The execution context of a command is usually controlled by the UI\nController\/ViewModel. It might be affected by the UI alright, but it&#8217;s the\nultimate decision of the ViewModel to enable or disable a command based on some\ndomain specific context. The sample code below will give a practical example how\nto to enable or disable a command&#8217;s execution context based on a user&#8217;s input.<\/p>\n<h3>Additional WinForms Binding Features in .NET 7<\/h3>\n<p>In addition to the new binding features, we added a new general data binding\ninfrastructure feature on <code>Control<\/code>: For an easier cascading of data source\npopulation in nested Forms (for example a form holds UserControls which hold\nother UserControls which hold custom controls etc.), .NET 7 also introduced a\n<strong><code>DataContext<\/code> property<\/strong> of type <code>Object<\/code> on <code>Control<\/code>. This property has\nambient characteristics (like <code>BackColor<\/code> or <code>Font<\/code>). That means when you assign\na data source instance to <code>DataContext<\/code>, that instance gets automatically\ndelegated down to every child control of the form. Currently, the <code>DataContext<\/code>\nproperty does simply serve the purpose of a data source carrier, but does not\naffect any bindings directly. It is still the duty of the control to then\ndelegate a new data source down to the respective <code>BindingSource<\/code> components,\nwhere it makes sense. Examples:<\/p>\n<ul>\n<li>UserControls, which are used inside of Forms, utilize dedicated\n<code>BindingSource<\/code> components for internal binding scenarios. They all need to be\ntaken from one central data source. This data source can now be handed down\nfrom the parent control via its <code>DataContext<\/code> property. When the <code>DataContext<\/code>\nproperty gets assigned to the form, not only will every child control of the\ncontrols collection of this parent have that same <code>DataContext<\/code> &#8211; as soon as\nthe data source of the parent&#8217;s <code>DataContext<\/code> changes, all the children\nreceive the <a href=\"https:\/\/learn.microsoft.com\/dotnet\/api\/system.windows.forms.control.datacontextchanged?view=windowsdesktop-7.0\"><strong>DataContextChange\nevent<\/strong><\/a>,\nso they know they can provide their <code>BindingSource<\/code>&#8216;s <code>DataSource<\/code> properties\nwith whatever updated data source their domain-specific context requires. We\ncover this scenario also in the sample app down below.<\/li>\n<li>If you have implemented data binding scenarios with custom binding engines,\nyou can also use <code>DataContext<\/code> to simplify binding scenarios and make them\nmore robust. In derived controls, you can overwrite\n<a href=\"https:\/\/learn.microsoft.com\/dotnet\/api\/system.windows.forms.control.ondatacontextchanged?view=windowsdesktop-7.0\"><strong><code>OnDataContextChanged<\/code><\/strong><\/a>\nto control the change notification of the <code>DataContext<\/code>, and you can use\n<a href=\"https:\/\/learn.microsoft.com\/dotnet\/api\/system.windows.forms.control.onparentfontchanged?view=windowsdesktop-7.0\"><strong><code>OnParentDataContextChanged<\/code><\/strong><\/a>\nto intercept notifications, when the parent control notifies its child\ncontrols that the <code>DataContext<\/code> property has changed.<\/li>\n<\/ul>\n<h2>Binding Commands and ViewModels with the WinForms out-of-proc Designer<\/h2>\n<p>Now, let&#8217;s put all of the puzzle pieces we&#8217;ve covered so far together, and apply\nthem in a very simple WinForms App:<\/p>\n<p><img decoding=\"async\" src=\"https:\/\/devblogs.microsoft.com\/dotnet\/wp-content\/uploads\/sites\/10\/2023\/01\/SimpleWinFormsMvvmView.png\" alt=\"A WinForms form in the Designer with a CheckBox, a Button, a Label, serving as a sample MVVM view.\" \/><\/p>\n<p>The idea here is to have a form which is controlled by a ViewModel, providing a\nCommand and properties to bind against the CheckBox control and the Label. When\nthe Button is engaged, the bound command in the ViewModel gets executed,\nchanging the <code>CommandResult<\/code> property which states how often the Button has been\nclicked. Since <code>CommandResult<\/code> is bound against the Label, the UI reflects this\nresult. The CheckBox in this scenario controls the availability of the command.\nWhen the CheckBox is checked, the command is available. Therefore, the button is\nenabled, since the command&#8217;s CanExecute method returns <code>true<\/code>. As soon as the\nCheckBox&#8217; check state changes, the bound <code>SampleCommandAvailability<\/code> gets\nupdated, and its setter gets executed. That in turn invokes the\n<code>NotifyCanExecuteChanged<\/code> method. That again triggers the execution of the\ncommand&#8217;s <code>CanExecute<\/code> method, which now returns the updated execution context\nand automatically updates the enabled state of the bound button so it becomes\ndisabled.  <\/p>\n<p>The business logic for this application is completely implemented in the\nViewModel. Except for what is in <code>InitializeComponent<\/code> to setup the form&#8217;s\ncontrols, the form only holds the code to setup the ViewModel as the form&#8217;s data\nsource.<\/p>\n<pre><code class=\"language-cs\">public class SimpleCommandViewModel : INotifyPropertyChanged\n    {\n        \/\/ The event that is fired when a property changes.\n        public event PropertyChangedEventHandler? PropertyChanged;\n\n        \/\/ Backing field for the properties.\n        private bool _sampleCommandAvailability;\n        private RelayCommand _sampleCommand;\n        private string _sampleCommandResult = \"* not invoked yet *\";\n        private int _invokeCount;\n\n        public SimpleCommandViewModel()\n        {\n            _sampleCommand = new RelayCommand(ExecuteSampleCommand, CanExecuteSampleCommand);\n        }\n\n        \/\/\/ &lt;summary&gt;\n        \/\/\/  Controls the command availability and is bound to the CheckBox of the Form.\n        \/\/\/ &lt;\/summary&gt;\n        public bool SampleCommandAvailability\n        {\n            get =&gt; _sampleCommandAvailability;\n            set\n            {\n                if (_sampleCommandAvailability == value)\n                {\n                    return;\n                }\n\n                _sampleCommandAvailability = value;\n\n                \/\/ When this property changes we need to notify the UI that the command availability has changed.\n                \/\/ The command's availability is reflected through the button's enabled state, which is - \n                \/\/ because its command property is bound - automatically updated.\n                _sampleCommand.NotifyCanExecuteChanged();\n\n                \/\/ Notify the UI that the property has changed.\n                OnPropertyChanged();\n            }\n        }\n\n        \/\/\/ &lt;summary&gt;\n        \/\/\/  Command that is bound to the button of the Form.\n        \/\/\/  When the button is clicked, the command is executed.\n        \/\/\/ &lt;\/summary&gt;\n        public RelayCommand SampleCommand\n        {\n            get =&gt; _sampleCommand;\n            set\n            {\n                if (_sampleCommand == value)\n                {\n                    return;\n                }\n\n                _sampleCommand = value;\n                OnPropertyChanged();\n            }\n        }\n\n        \/\/\/ &lt;summary&gt;\n        \/\/\/  The result of the command execution, which is bound to the Form's label.\n        \/\/\/ &lt;\/summary&gt;\n        public string SampleCommandResult\n        {\n            get =&gt; _sampleCommandResult;\n            set\n            {\n                if (_sampleCommandResult == value)\n                {\n                    return;\n                }\n\n                _sampleCommandResult = value;\n                OnPropertyChanged();\n            }\n        }\n\n        \/\/\/ &lt;summary&gt;\n        \/\/\/  Method that is executed when the command is invoked.\n        \/\/\/ &lt;\/summary&gt;\n        public void ExecuteSampleCommand()\n            =&gt; SampleCommandResult = $\"Command invoked {_invokeCount++} times.\";\n\n        \/\/\/ &lt;summary&gt;\n        \/\/\/  Method that determines whether the command can be executed. It reflects the \n        \/\/\/  property CommandAvailability, which in turn is bound to the CheckBox of the Form.\n        \/\/\/ &lt;\/summary&gt;\n        public bool CanExecuteSampleCommand()\n            =&gt; SampleCommandAvailability;\n\n        \/\/ Notify the UI that one of the properties has changed.\n        private void OnPropertyChanged([CallerMemberName] string propertyName = \"\")\n            =&gt; PropertyChanged?.Invoke(this, new PropertyChangedEventArgs(propertyName));\n    }<\/code><\/pre>\n<p>Setting up the form and the ViewModel through binding in WinForms is of course\ndifferent than it is in typical XAML languages like WPF, UWP or .NET MAUI. But it&#8217;s\npretty quick and 100% in the spirit of WinForms.<\/p>\n<p><strong>Note:<\/strong> Please keep in mind that the out-of-process Designer doesn&#8217;t support\nthe <em>Data Source Provider Service<\/em>, which is responsible for providing the\nclassic Framework Data Sources Window. The <a href=\"https:\/\/devblogs.microsoft.com\/dotnet\/databinding-with-the-oop-windows-forms-designer\/\">data binding blog\npost<\/a>\ntells more about the background. So, in a .NET WinForms App at this point you\ncannot interactively create Typed DataSets with the Designer or add existing\nTyped DataSets as data sources through the Data Sources tool window. Keep also\nin mind that although there is no Designer support to <em>add<\/em> Typed DataSets as\ndata sources, the out-of-process Designer for .NET does support binding against\nTyped DataSets of already defined data sources (which have been brought over\nfrom a .NET Framework application just by copying the files structure of a\nproject).<\/p>\n<p>The out-of-process Designer provides an easier alternative to hook up new Object\nData Sources, which can be based on ViewModels as described here, but also based\non classes which results from Entity Framework or EFCore. The Microsoft docs\n<a href=\"https:\/\/learn.microsoft.com\/ef\/core\/get-started\/winforms\">provide a neat guide<\/a>\nhow to work with EFCore and this new Feature to create a simple data bound\nWinForms application.<\/p>\n<p>To set up the bindings for the ViewModel to the sample WinForms UI, follow these\nsteps:<\/p>\n<ol>\n<li>\n<p>Open and design the form in the WinForms out-of-process Designer according to the screenshot above.<\/p>\n<\/li>\n<li>\n<p>Select the Button control by clicking on it.<\/p>\n<\/li>\n<li>\n<p>In the Property Browser, scroll to the top, find the <em>(DataBindings)<\/em> property\nand open it.<\/p>\n<\/li>\n<li>\n<p>Find the row for the <code>Command<\/code> property, and open the Design Binding Picker by\nclicking the arrow-down button at the end of the cell.<\/p>\n<p><img decoding=\"async\" src=\"https:\/\/devblogs.microsoft.com\/dotnet\/wp-content\/uploads\/sites\/10\/2023\/01\/EngageAddDataSourceDialog.png\" alt=\"Screenshot showing the open Design Binding Picker to add a new object data source.\" \/><\/p>\n<\/li>\n<li>\n<p>In the Design Binding Picker, click on <em>Add new Object Data Source<\/em>.<\/p>\n<\/li>\n<li>\n<p>The Designer now shows the <em>Add Object Data Source<\/em>-Dialog. In this dialog,\nclick on the class you want to add, and then click <em>OK<\/em>.<\/p>\n<p><img decoding=\"async\" src=\"https:\/\/devblogs.microsoft.com\/dotnet\/wp-content\/uploads\/sites\/10\/2023\/01\/AddNewDataSourceDialog.png\" alt=\"Screenshot showing the new Add Object Data Source dialog.\" \/><\/p>\n<\/li>\n<li>\n<p>After closing the dialog, the new data source becomes available, and you can\nfind the <code>SampleCommand<\/code> property in the Design Binding Picker and assign it to\nthe Button&#8217;s <code>Command<\/code> property.<\/p>\n<p><img decoding=\"async\" src=\"https:\/\/devblogs.microsoft.com\/dotnet\/wp-content\/uploads\/sites\/10\/2023\/01\/PickCommandFromDesignBindingPicker.png\" alt=\"Screenshot showing how to pick a command from a ViewModel in the Design Binding Picker.\" \/><\/p>\n<\/li>\n<li>\n<p>Select the CheckBox control in the form, and bind its <code>Checked<\/code> property to\nthe ViewModel&#8217;s <code>CommandAvailability<\/code> property. Please note from the following\nscreenshot: The previous step automatically inserted the required\n<code>BindingSource<\/code> component, which is in most cases common to use as a mediator\nfor binding and syncing between several control instances (like the current\nline of a bound DataGridView and a detail view on the same Form). When you\nearlier picked the <code>SampleCommand<\/code> property directly from the ViewModel, the\nDesigner created the BindingSource based on that pick and then selected that\nproperty from the BindingSource. Successive bindings on this form should now\nbe picked directly from that BindingSource instance.<\/p>\n<p><img decoding=\"async\" src=\"https:\/\/devblogs.microsoft.com\/dotnet\/wp-content\/uploads\/sites\/10\/2023\/01\/BindCheckPropertyToCommandAvailibility.png\" alt=\"Screenshot showing the binding of the CheckBox against CommandAvailability of the ViewModel.\" \/>    <\/p>\n<\/li>\n<li>\n<p>Select the Label control in the form, and bind its <code>Text<\/code> property to the\nViewModel&#8217;s <code>CommandResult<\/code> property.<\/p>\n<\/li>\n<\/ol>\n<p>The only code now which needs to be run in the form directly, is the hook up of the ViewModel with the form using the BindingSource at runtime:<\/p>\n<pre><code class=\"language-cs\">        protected override void OnLoad(EventArgs e)\n        {\n            base.OnLoad(e);\n            simpleCommandViewModelBindingSource.DataSource = new SimpleCommandViewModel();\n        }<\/code><\/pre>\n<h3>Using the MVVM community toolkit for streamlined coding<\/h3>\n<p>For more complex scenarios, developing the domain-specific MVVM classes would\nrequire writing comparatively expensive boilerplate code. Typically, developers\nusing XAML-based UI stacks like WPF or .NET MAUI use a library called <a href=\"https:\/\/learn.microsoft.com\/windows\/communitytoolkit\/mvvm\/introduction\">MVVM Community\nToolkit<\/a>\nto utilize the many provided MVVM-base classes of that library, but also to let\ncode generators do the writing of this kind of code wherever it makes sense.<\/p>\n<p>To use the MVVM community toolkit, you just need to add the respective <a href=\"https:\/\/www.nuget.org\/packages\/CommunityToolkit.Mvvm\/\">NuGet\nreference<\/a>\n<em>CommunityToolkit.Mvvm<\/em> to the project which is hosting the ViewModel classes\nfor your app.<\/p>\n<p><img decoding=\"async\" src=\"https:\/\/devblogs.microsoft.com\/dotnet\/wp-content\/uploads\/sites\/10\/2023\/01\/AddMvvmCommunityToolkitNuGet.png\" alt=\"Screenshot showing how to add the Microsoft CommunityToolkit.MVVM package to a project\" \/><\/p>\n<p>The introduction to the MVVM community toolkit explains the steps in more\ndetail.<\/p>\n<p>Our more complex MVVM-Editor sample uses the Toolkit for different disciplines:<\/p>\n<ul>\n<li><strong><code>ObservableObject<\/code>:<\/strong> ViewModels in the Editor sample app use\n<a href=\"https:\/\/learn.microsoft.com\/windows\/communitytoolkit\/mvvm\/observableobject\"><code>ObservableObject<\/code><\/a>\nas their base class (indirectly through <code>WinFormsViewController<\/code> &#8211; take a look\nat the source code of the sample for additional background info). It\nimplements <code>INotifyPropertyChanged<\/code> and encapsulates all the necessary\nproperty notification Infrastructure.<\/li>\n<li><strong><code>RelayCommand<\/code>:<\/strong> If the dedicated implementation of Commands is necessary,\nuse the Toolkit&#8217;s\n<a href=\"https:\/\/learn.microsoft.com\/windows\/communitytoolkit\/mvvm\/relaycommand\"><code>RelayCommand<\/code><\/a>,\nwhich is an extended version of the class which you already learned about\nearlier.<\/li>\n<\/ul>\n<p>What really helps saving time though, are the code generators the MVVM Community\nToolkit provides. Instead of writing the implementation for a bindable ViewModel\nproperty yourself, you just need to apply the <a href=\"https:\/\/learn.microsoft.com\/dotnet\/communitytoolkit\/mvvm\/generators\/observableproperty\"><code>ObservableProperty<\/code>\nattribute<\/a>\nover the backing field, and the code generators do the rest:<\/p>\n<pre><code class=\"language-cs\">    \/\/\/ &lt;summary&gt;\n    \/\/\/  UI-Controller class for controlling the main editor Window and most of the editor's functionality.\n    \/\/\/ &lt;\/summary&gt;\n    public partial class MainFormController : WinFormsViewController\n    {\n        \/\/\/ &lt;summary&gt;\n        \/\/\/  Current length of the selection.\n        \/\/\/ &lt;\/summary&gt;\n        [ObservableProperty]\n        private int _selectionLength;<\/code><\/pre>\n<p>You can save even more time by using the <a href=\"https:\/\/learn.microsoft.com\/dotnet\/communitytoolkit\/mvvm\/generators\/relaycommand\"><code>RelayCommand<\/code>\nattribute<\/a>,\nwhich you put on top of the command methods of your ViewModel. In this case, the\n<code>Command<\/code> property which you need to bind against the View is completely\ngenerated by the Toolkit, along with the code which hooks up the command. If the\ncommand needs to take a related <code>CanExecuteCommand<\/code> method into account in\naddition, you can provide that method like shown in the code snippet below. It\ndoesn&#8217;t really matter if the method is an async method or not. In this example,\nconverting the whole text into upper case is done inside a dedicated task to\nshow that asynchronous methods are in WinForms as valid as synchronous methods\nas a base for command code generation.<\/p>\n<pre><code class=\"language-cs\">        [RelayCommand(CanExecute = nameof(CanExecuteContentDependingCommands))]\n        private async Task ToUpperAsync()\n        {\n            string tempText = null!;\n            var savedSelectionIndex = SelectionIndex;\n\n            await Task.Run(() =&gt;\n            {\n                var upperText = TextDocument[SelectionIndex..(SelectionIndex + SelectionLength)].ToUpper();\n\n                tempText = string.Concat(\n                    TextDocument[..SelectionIndex].AsSpan(),\n                    upperText.AsSpan(),\n                    TextDocument[(SelectionIndex + SelectionLength)..].AsSpan());\n            });\n\n            TextDocument = tempText;\n            SelectionIndex = savedSelectionIndex;\n        }<\/code><\/pre>\n<p>Those are just a few examples, how the Toolkit supports you, and how the Editor\nsample app uses the Toolkit in several spots. Refer to the toolkit&#8217;s\ndocumentation for additional information.<\/p>\n<h3>Honoring Preview Features in the Runtime and the out-of-proc WinForms Designer<\/h3>\n<p>The WinForms Command Binding feature is currently under preview. That means, we\nmight introduce additional functionality for the .NET 8 time frame for it or\nslightly change implementation details, based on feedback. So, feedback is\nreally important to us, especially with this feature!<\/p>\n<p>When you use features which have been marked as in preview &#8211; and please note,\nthat also in a release version of .NET there can be features still in preview &#8211;\nyou need to acknowledge in your app that you aware of using a preview feature.\nYou do that by adding a special tag named <code>EnablePreviewFeatures<\/code> into your\n<em>csproj<\/em> file (or <em>vbproj<\/em> for Visual Basic .NET 7 projects), like this. The\n<a href=\"https:\/\/github.com\/dotnet\/designs\/blob\/main\/accepted\/2021\/preview-features\/preview-features.md\">Preview Features Design\nDocument<\/a>\ndescribes this feature in detail.<\/p>\n<pre><code class=\"language-xml\">&lt;Project Sdk=\"Microsoft.NET.Sdk\"&gt;\n\n  &lt;PropertyGroup&gt;\n    &lt;EnablePreviewFeatures&gt;true&lt;\/EnablePreviewFeatures&gt;\n    &lt;OutputType&gt;WinExe&lt;\/OutputType&gt;\n    &lt;TargetFramework&gt;net7.0-windows&lt;\/TargetFramework&gt;\n    &lt;UseWindowsForms&gt;true&lt;\/UseWindowsForms&gt;\n    &lt;LangVersion&gt;10.0&lt;\/LangVersion&gt;\n    &lt;Nullable&gt;enable&lt;\/Nullable&gt;\n  &lt;\/PropertyGroup&gt;<\/code><\/pre>\n<p>This way, the whole assembly is automatically attributed with\n<a href=\"https:\/\/learn.microsoft.com\/dotnet\/api\/system.runtime.versioning.requirespreviewfeaturesattribute?view=net-7.0\"><code>RequiresPreviewFeatures<\/code><\/a>.\nIf you omit this, and you use preview features of the WinForms runtime, like the\n<code>Command<\/code> property of a button control in .NET 7, you would see the following\nerror message:<\/p>\n<p><img decoding=\"async\" src=\"https:\/\/devblogs.microsoft.com\/dotnet\/wp-content\/uploads\/sites\/10\/2023\/01\/PreviewFeaturesErrorList.png\" alt=\"Screenshot of the error list tool window showing messages which result from using runtime features  marked in preview.\" \/><\/p>\n<p>In addition, if you tried to bind against a property of the runtime in preview,\ninstead of the Design Binding Picker, you would see an error message, stating\nthat you needed to enable preview features as described.<\/p>\n<p><img decoding=\"async\" src=\"https:\/\/devblogs.microsoft.com\/dotnet\/wp-content\/uploads\/sites\/10\/2023\/01\/PreviewFeaturesDesignBindingPicker.png\" alt=\"Screenshot of the Design Binding Picker with message that binding to properties in preview is not allowed.\" \/><\/p>\n<h2>Reusing WinForms ViewModels in .NET MAUI Apps<\/h2>\n<p>Examining the WinForms sample app, you will see that the actual MainForm of the app doesn&#8217;t consist of a lot of code:<\/p>\n<pre><code class=\"language-cs\">public partial class MainForm : Form\n{\n    public MainForm()\n    {\n        InitializeComponent();\n    }\n\n    protected override void OnLoad(EventArgs e)\n    {\n        base.OnLoad(e);\n        DataContext = new MainFormController(SimpleServiceProvider.GetInstance());\n    }\n\n    private void MainForm_DataContextChanged(object sender, EventArgs e)\n        =&gt; _mainFormControllerBindingSource.DataSource = DataContext;\n}\n<\/code><\/pre>\n<p>This is really all there is: On loading the app&#8217;s main form, we create an\ninstance of the <code>MainFormController<\/code> and pass in a service provider. The\n<code>MainFormController<\/code> serves as the ViewModel which holds every aspect of the\nbusiness logic &#8211; the animated gif above does show, what that means: Reporting\nthe cursor position, creating a new document, wrapping text or converting the\nwhole text to upper case characters &#8211; the ViewModel provides every command to do\nthat, and all the methods are assigned to the view (the main form) via command\nbinding.<\/p>\n<p>We already saw how the command binding is done with the new Command Binding\nfeatures in WinForms .NET 7. In .NET MAUI, command binding to an existing\nViewModel can be done via <a href=\"https:\/\/learn.microsoft.com\/dotnet\/maui\/xaml\/fundamentals\/data-binding-basics?view=net-maui-7.0\">XAML data\nbinding<\/a>.\nWithout going too much into detail of that actual topic, this is a small excerpt\nof the .NET MAUI sample app&#8217;s XAML code:<\/p>\n<pre><code class=\"language-xaml\">&lt;?xml version=\"1.0\" encoding=\"utf-8\" ?&gt;\n&lt;ContentPage xmlns=\"http:\/\/schemas.microsoft.com\/dotnet\/2021\/maui\"\n             xmlns:x=\"http:\/\/schemas.microsoft.com\/winfx\/2009\/xaml\"\n             x:Class=\"MauiEdit.MainPage\"&gt;\n\n    &lt;Shell.TitleView&gt;\n        &lt;Grid Margin=\"0,8,0,0\"&gt;\n            &lt;Grid.ColumnDefinitions&gt;\n                &lt;ColumnDefinition Width=\"*\"\/&gt;\n                &lt;ColumnDefinition Width=\"Auto\"\/&gt;\n            &lt;\/Grid.ColumnDefinitions&gt;\n\n            &lt;Label \n                Margin=\"20,0,0,0\"\n                Text=\"WinForms\/Maui Edit\"\n                FontAttributes=\"Bold\"\n                FontSize=\"32\"\/&gt;\n\n            &lt;HorizontalStackLayout \n                Grid.Column=\"1\"&gt;\n\n                &lt;Button \n                    Margin=\"0,0,10,0\"\n                    Text=\"New...\" \n                    HeightRequest=\"40\"\n                    Command=\"{Binding NewDocumentCommand}\"\/&gt;\n\n                &lt;Button \n                    Margin=\"0,0,10,0\"\n                    Text=\"Insert Demo Text\" \n                    HeightRequest=\"40\"\n                    Command=\"{Binding InsertDemoTextCommand}\"\/&gt;<\/code><\/pre>\n<p>Basically, while the WinForms designer provides a UI for linking up the commands\nof a data source with the form interactively, in XAML based UI stacks it is\ncommon practice to write the XAML code to design the UI, and add the binding\ndirectly in that process.<\/p>\n<p>The Microsoft docs hold more information about <a href=\"https:\/\/learn.microsoft.com\/dotnet\/maui\/xaml\/fundamentals\/mvvm?view=net-maui-7.0\">XAML data binding in the context\nof\nMVVM<\/a>\nand command binding (which is also called\n<a href=\"https:\/\/learn.microsoft.com\/dotnet\/maui\/xaml\/fundamentals\/mvvm?view=net-maui-7.0#commanding\">Commanding<\/a>).<\/p>\n<p>One additional aspect is important to point out in the context of reusing a\nViewModel for different UI stacks like WinForms and .NET MAUI: When the user\nclicks, as one example, on <em>New Document<\/em>, the respective command is executed in\nthe ViewModel. As you can observe in the application&#8217;s live demo gif: The user\nis then prompted in the WinForms version with a Task Dialog, and is asked if\ndeleting the current text is OK. Taking a look at the respective ViewModel&#8217;s\ncode, we see the following method:<\/p>\n<pre><code class=\"language-csharp\">    [RelayCommand(CanExecute = nameof(CanExecuteContentDependingCommands))]\n    private async Task NewDocumentAsync()\n    {\n        \/\/ So, this is how we control the UI via a Controller or ViewModel.\n        \/\/ We get the required Service over the ServiceProvider, \n        \/\/ which the Controller\/ViewModels got via Dependency Injection.\n        \/\/ Dependency Injection means, _depending_ on what UI-Stack (or even inside a Unit Test)\n        \/\/ we're actually running, the dialogService will do different things:\n\n        \/\/ * On WinForms it shows a WinForms MessageBox.\n        \/\/ * On .NET MAUI, it displays an alert.\n        \/\/ * In the context of a unit test, it doesn't show anything: the unit test,\n        \/\/   just pretends, the user had clicked the result button.\n        var dialogService = ServiceProvider.GetRequiredService&lt;IDialogService&gt;();\n\n        \/\/ Now we use this DialogService to remote-control the UI completely\n        \/\/ _and_ independent of the actual UI technology.\n        var buttonString = await dialogService.ShowMessageBoxAsync(\n            title: \"New Document\",\n            heading: \"Do you want to create a new Document?\",\n            message: \"You are about to create a new Document. The old document will be erased, changes you made will be lost.\",\n            buttons: new[] { YesButtonText, NoButtonText });\n\n        if (buttonString == YesButtonText)\n        {\n            TextDocument = string.Empty;\n        }\n    }<\/code><\/pre>\n<p>Of course, the ViewModel must not call WinForms TaskDialog directly. After all,\nthe ViewModel is supposed to be reused in or with other UI stacks and cannot\nhave any dependencies on assemblies of a <em>particular<\/em> UI stack. So, when our\nViewModel is used in the context of a WinForms app, it&#8217;s supposed to show a\nWinForms\n<a href=\"https:\/\/learn.microsoft.com\/dotnet\/api\/system.windows.forms.taskdialog?view=windowsdesktop-7.0\">TaskDialog<\/a>.\nIf, however, it&#8217;s run in the context of a .NET MAUI app, it is supposed to\n<a href=\"https:\/\/learn.microsoft.com\/dotnet\/maui\/user-interface\/pop-ups?view=net-maui-7.0\">display an\nalert<\/a>.\n<em>Depending<\/em> on in what context the ViewModel is executed, it effectively needs\nto do different things. To overcome this, we <em>inject<\/em> the ViewModel on\ninstantiation with a service provider, which provides an abstract way to\ninteract with the respective UI elements. In WinForms, we pass the service for a\nWinForms dialog service. In .NET MAUI, we pass the service for a .NET MAUI\ndialog service:<\/p>\n<pre><code class=\"language-csharp\">    public static MauiApp CreateMauiApp()\n    {\n        var builder = MauiApp.CreateBuilder();\n\n        \/\/ We pass the dialog service to the service provider, so we can use it in the view models.\n        builder.Services.AddSingleton(typeof(IDialogService), new MauiDialogService());\n\n        builder\n            .UseMauiApp&lt;App&gt;()\n            .ConfigureFonts(fonts =&gt;\n            {\n                fonts.AddFont(\"OpenSans-Regular.ttf\", \"OpenSansRegular\");\n                fonts.AddFont(\"OpenSans-Semibold.ttf\", \"OpenSansSemibold\");\n            });\n\n#if DEBUG\n        builder.Logging.AddDebug();\n#endif\n\n        return builder.Build();\n    }<\/code><\/pre>\n<p>With this, the ViewModel doesn&#8217;t need to know what exactly is going to happen,\nif for example the <code>dialogService.ShowMessageAsync<\/code> is called. <code>DialogService<\/code>\nwill call different things <em>depending<\/em> on the UI context. This is the reason\nthis approach is called <em>dependency injection<\/em>. The easiest way to learn and get\na feeling what exactly is happening in both cases, is to just debug in single\nsteps through the code paths in both apps and observe what parts are being used\nin the respective UI stacks. Please also note, that this sample is using the\ndialog service in a very simplistic way. You can find more powerful libraries on\nthe web which are dedicated to that purpose.<\/p>\n<h3>Unit testing ViewModels with dependency injection<\/h3>\n<p>The Editor sample solution uses the same approach to provide a Unit Test (inside\nthe solution&#8217;s unit test project) for the ViewModel. In this case, the ViewModel\nalso gets injected with the service provider to retrieve a dialog service at\nruntime. This time, however, the dialog service&#8217;s purpose is not to show\nsomething visually or interact with the user, but to rather emulate the user&#8217;s\ninput:<\/p>\n<pre><code class=\"language-csharp\">    public Task&lt;string&gt; ShowMessageBoxAsync(\n        string title, string heading, string message, params string[] buttons)\n    {\n        ShowMessageBoxResultEventArgs eArgs = new();\n        ShowMessageBoxRequested?.Invoke(this, eArgs);\n\n        if (eArgs.ResultButtonText is null)\n        {\n            throw new NullReferenceException(\"MessageBox test result can't be null.\");\n        }\n\n        return Task.FromResult(eArgs.ResultButtonText);\n    }<\/code><\/pre>\n<p>When the ViewModel is supposed to show the MessageBox, rather than to actually\nshow an UI component, an event is fired. This event can be then handled by the\nunit test method, and the emulated user response is just passed as the event\nresult:<\/p>\n<pre><code class=\"language-csharp\">        .\n        .\n        .\n        \/\/ We simulate the user requesting to 'New' the document,\n        \/\/ but says \"No\" on the MessageDialogBox to actually clear it.\n        dialogService!.ShowMessageBoxRequested += DialogService_ShowMessageBoxRequested;\n\n        \/\/ We test the first time; our state machine returns \"No\" the first time.\n        await mainFormController.NewDocumentCommand.ExecuteAsync(null);\n        Assert.Equal(MainFormController.GetTestText(), mainFormController.TextDocument);\n\n        \/\/ We test the second time; our state machine returns \"Yes\" the first time.\n        await mainFormController.NewDocumentCommand.ExecuteAsync(null);\n        Assert.Equal(String.Empty, mainFormController.TextDocument);\n\n        void DialogService_ShowMessageBoxRequested(object? sender, ShowMessageBoxResultEventArgs e)\n            =&gt; e.ResultButtonText = dialogState++ switch {\n                0 =&gt; MainFormController.NoButtonText,\n                1 =&gt; MainFormController.YesButtonText,\n                _ =&gt; string.Empty\n            };\n<\/code><\/pre>\n<h2>Summary<\/h2>\n<p>Command Binding in WinForms will make it easier to modernize WinForms\napplications in a feasible way. Separating the UI from the business logic by\nintroducing UI Controller can be done step by step over time. Introducing unit\ntests will make your WinForms app more robust. Using ViewModels in additional UI\nstacks like .NET MAUI allows you to take parts of a LOB app cross-platform and\nhave Mobile Apps for areas where it makes sense. Additionally, the adoption of\nAzure services becomes much easier with a sound architecture, and essential code\ncan also be easily shared with the Mobile App&#8217;s spin-off.<\/p>\n<p>Feedback about the subject matter is really important to us, so\nplease let us know your thoughts and additional ideas! We&#8217;re also interested\nabout what additional topics of this area you would like hear about from us.\nPlease also note that the WinForms .NET runtime is open source, and you can\ncontribute! If you have general feature ideas, encountered bugs, or even want to\ntake on existing issues around the WinForms runtime and submit PRs, have a look\nat the <a href=\"https:\/\/github.com\/dotnet\/winforms\">WinForms Github repo<\/a>. If you have\nsuggestions around the WinForms Designer, feel free to file new issues there as\nwell.<\/p>\n<p>Happy coding!<\/p>\n","protected":false},"excerpt":{"rendered":"<p>The WinForms code-behind approach has always made app development in WinForms unrivaled fast. For complex line-of-business apps, however, it can become an architectural challenge. New Command- and Data Binding Features in .NET 7 make UI-Controllers and MVVM an alternative and allow them also be reused in UI stacks like .NET MAUI.<\/p>\n","protected":false},"author":9483,"featured_media":44138,"comment_status":"open","ping_status":"","sticky":false,"template":"","format":"standard","meta":{"_acf_changed":false,"footnotes":""},"categories":[685,7233,756,7199,7163],"tags":[],"class_list":["post-44066","post","type-post","status-publish","format-standard","has-post-thumbnail","hentry","category-dotnet","category-maui","category-csharp","category-visual-basic","category-winforms"],"acf":[],"blog_post_summary":"<p>The WinForms code-behind approach has always made app development in WinForms unrivaled fast. For complex line-of-business apps, however, it can become an architectural challenge. New Command- and Data Binding Features in .NET 7 make UI-Controllers and MVVM an alternative and allow them also be reused in UI stacks like .NET MAUI.<\/p>\n","_links":{"self":[{"href":"https:\/\/devblogs.microsoft.com\/dotnet\/wp-json\/wp\/v2\/posts\/44066","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\/9483"}],"replies":[{"embeddable":true,"href":"https:\/\/devblogs.microsoft.com\/dotnet\/wp-json\/wp\/v2\/comments?post=44066"}],"version-history":[{"count":0,"href":"https:\/\/devblogs.microsoft.com\/dotnet\/wp-json\/wp\/v2\/posts\/44066\/revisions"}],"wp:featuredmedia":[{"embeddable":true,"href":"https:\/\/devblogs.microsoft.com\/dotnet\/wp-json\/wp\/v2\/media\/44138"}],"wp:attachment":[{"href":"https:\/\/devblogs.microsoft.com\/dotnet\/wp-json\/wp\/v2\/media?parent=44066"}],"wp:term":[{"taxonomy":"category","embeddable":true,"href":"https:\/\/devblogs.microsoft.com\/dotnet\/wp-json\/wp\/v2\/categories?post=44066"},{"taxonomy":"post_tag","embeddable":true,"href":"https:\/\/devblogs.microsoft.com\/dotnet\/wp-json\/wp\/v2\/tags?post=44066"}],"curies":[{"name":"wp","href":"https:\/\/api.w.org\/{rel}","templated":true}]}}