{"id":38578,"date":"2022-02-01T12:30:49","date_gmt":"2022-02-01T19:30:49","guid":{"rendered":"https:\/\/devblogs.microsoft.com\/dotnet\/?p=38578"},"modified":"2022-02-01T12:54:10","modified_gmt":"2022-02-01T19:54:10","slug":"databinding-with-the-oop-windows-forms-designer","status":"publish","type":"post","link":"https:\/\/devblogs.microsoft.com\/dotnet\/databinding-with-the-oop-windows-forms-designer\/","title":{"rendered":"Databinding with the OOP Windows Forms Designer"},"content":{"rendered":"<p>The design-time support for databinding in the new Windows Forms (WinForms) .NET\nOut of Process (OOP) Designer is different from the Framework Designer. The\nWinForms OOP Designer has a new and easier approach for hooking up data sources,\nfocusing on <em>Object<\/em> Data Sources to support .NET based <a href=\"https:\/\/en.wikipedia.org\/wiki\/Object%E2%80%93relational_mapping\">object relational\nmapper<\/a>\ntechnologies (like the latest version of <a href=\"https:\/\/docs.microsoft.com\/ef\/core\/\">Entity Framework Core \u2013 EF\nCore<\/a> for short) which the WinForms team\nrecommends as a successor for Typed DataSets. This new approach was due to the\ncompletely different architecture of the new WinForms OOP Designer, which we\nhave discussed <a href=\"https:\/\/devblogs.microsoft.com\/dotnet\/state-of-the-windows-forms-designer-for-net-applications\/\">in the previous blog\npost<\/a>.\nIf you haven\u2019t read it yet, you should do so first, as it is essential for a\nbetter understanding of this post.<\/p>\n<h2>Why is the Data Source Tool Window unavailable in .NET projects?<\/h2>\n<p>Essential to databinding in WinForms .NET Framework is the <em>Data Source Provider\nService<\/em>. This service runs in Visual Studio, and its responsibilities are as\nfollows:<\/p>\n<ul>\n<li>\n<p>It generates and maintains Typed DataSets by connecting to a database data\nsource (for example <em>Microsoft SQL Server<\/em> or <em>Oracle DB Server<\/em>).<\/p>\n<\/li>\n<li>\n<p>It detects types which are designed to act either as <em>Typed DataSet Data\nSources<\/em> or <em>Object Data Sources<\/em>.<\/p>\n<\/li>\n<li>\n<p>It identifies potential <em>Object Data Sources<\/em> and sets those up in the\nproject.<\/p>\n<\/li>\n<li>\n<p>It discovers legacy (for example SOAP-based) web services and sets them up\nin a way so they can act as data sources.<\/p>\n<\/li>\n<li>\n<p>It provides the UI functionality for the <em>Data Source Tool Window<\/em> in .NET\nFramework for WPF and WinForms applications. It also provides the UI Wizard\nto add new or maintain existing SQL Server connected data sources.<\/p>\n<\/li>\n<\/ul>\n<p>As of today, the Data Source Provider Service only works in the context of\nVisual Studio, which means it can only type-resolve .NET Framework assemblies\nand types. For .NET in its current version, the Data Source Provider Service is\nnot able to retrieve the necessary type information as it would need to operate\non the .NET Server Side (the\n<a href=\"https:\/\/devblogs.microsoft.com\/dotnet\/state-of-the-windows-forms-designer-for-net-applications\/#enter-the-designtoolsserver\"><em>DesignToolsServer<\/em><\/a>).\nThis is the reason that the UI stacks which used to rely on the Data Source\nProvider Service (WinForms, WPF) need to come up with alternatives for setting\nup new data sources and at the same time support legacy scenarios as well as\npossible. Providing feasible migration options, so that data access and\ndatabinding technologies can be migrated Form by Form, with both data source\nbinding approaches (Typed DataSets <em>and<\/em> new ORMs based on Object Data Sources)\npresent over a period of time, was the main driver for the new databinding\nfunctionality.<\/p>\n<h2>Working with legacy Typed DataSets in the OOP Designer<\/h2>\n<p>To decouple WinForms from the dependency to the Data Source Provider Service,\nthere is now a new and quicker way to hook up new Object Data Sources.<\/p>\n<p>That said, existing Typed DataSets definitions copied from Framework projects\ncan \u2013 with some limitations \u2013 be consumed by the OOP Designer even without that\nservice present. This means, data-bound Forms or UserControls using Typed\nDataSets can be opened, and the Design Binding Picker (the drop-down editor in\nthe Property Browser to pick data sources for binding) will continue to provide\nthe necessary functionality to define the databinding of individual properties\nof controls. At this time, though, no <em>new<\/em> Typed DataSets can be generated in\nthe context of a WinForms .NET application. It is also not possible, to\ninteractively update the schema for a Typed DataSet by querying the schema of\nthe assigned database. Necessary components (<code>DataSet<\/code> and for assigning the\ndata at runtime <code>tablenameTableAdapter<\/code>) to add a new binding definition can,\nhowever, be added from the toolbox and hooked up manually \u2013 which means\n<em>maintaining<\/em> legacy data-bound forms based on Typed Data Sets in .NET WinForms\nprojects is generally supported.<\/p>\n<p>The following animated gif shows the process. Copy the Typed DataSet definition\nfrom your existing Framework project to your new .NET project and see that all\nnecessary adapters and DataSets automatically appear in the toolbox on\nrecompile. You see: Clicking the Typed DataSet based data source on the Picker\ndoes only set up the binding if the respective components are present in the\nComponent Tray.<\/p>\n<p><img decoding=\"async\" src=\"https:\/\/devblogs.microsoft.com\/dotnet\/wp-content\/uploads\/sites\/10\/2022\/02\/LegacyDataSets.gif\" alt=\"An animated gif showing how to prepare a Form for using Typed DataSets as a data source for binding\" \/><\/p>\n<h2>New Approaches when using Object Data Source Binding<\/h2>\n<p>Object Data Sources can, in contrast to Typed Data Sets, get their data through\nall different kind of means. One of the most popular alternatives, which is a\ngreat replacement for old-fashioned Typed DataSets, is Entity Framework Core (EF\nCore for short). Apart from the fact that it has greater performance and a\nbigger set of functionalities compared to Typed Data Sets, it also uses a\ndifferent approach in dealing with the permanent task of updating and\nmaintaining a database\u2019s schema. While EF Core can principally be used in the\nsame way as Typed Datasets, which are generated based on an already existing\ndatabase, data objects based on EF Core can take a different more flexible and\nmore maintenance-friendly approach, which is called <em>Code first<\/em>.<\/p>\n<p><a href=\"https:\/\/docs.microsoft.com\/ef\/core\/#the-model\">Code-first in this context\nmeans<\/a>, the class\ndefinition defines the data structures\/schemas, the relations between the\nentities (tables), and then the actual database schema is derived from this\nclass definition: So-called migration-code updates the actual database\ndefinition on the fly. The advantage: The underlying database technologies is\nabstracted away: Code-first enables you to generate the schema for <a href=\"https:\/\/docs.microsoft.com\/ef\/core\/providers\/?tabs=dotnet-core-cli\">many\ndifferent database\nsystems<\/a>:\nSQL Server, SQLite, Oracle Server, In-Memory databases, Cosmos, PostgreSQL,\nMySql \u2013 you name it!<\/p>\n<p><img decoding=\"async\" src=\"https:\/\/devblogs.microsoft.com\/dotnet\/wp-content\/uploads\/sites\/10\/2022\/01\/DataClassesInProject.png\" alt=\"A screenshot of a C# code file in Visual Studio showing a typical EF Core code-first data class\" \/><\/p>\n<p>Let\u2019s consider the following scenario: We build a .NET 6 Windows Forms\napplication using <a href=\"https:\/\/docs.microsoft.com\/ef\/core\/\">EF Core<\/a> code-first with\ndata classes defined in a dedicated class library. This way, we can reuse the\ndata layer code in other projects. But &#8211; in contrast what you would have done\nwith Typed DataSets, we are not binding the EF Core data classes directly to the\nWinForms UI. The goal is to reduce the business logic code in the actual UI\n(Forms\/UserControls) and get rid as much as possible of the WinForms typical\n\u201cCode Behind\u201d style. For that, we are introducing a set of properties to bind to\nyet another Object Data Source, which implements the business logic instead. We\ncall this the <em>business logic UI-controller class<\/em>, or <em>UI-controller<\/em> for\nshort. And those are the properties, we bind. A few examples:<\/p>\n<ul>\n<li>\n<p>Instead of setting the window title text of a Form directly in code-behind\nin the Form, we have a property in the UI-controller for the windows title.\nAnd that we bind.<\/p>\n<\/li>\n<li>\n<p>A <em>Save<\/em> button should only be enabled when there actually is something to\nsave. Instead of enabling or disabling the button in Code-Behind in the\nForm, we are introducing for example a `SaveButtonEnabled` property in the\nUI-controller, which we then bind against the `Enabled` property of the\nbutton.<\/p>\n<\/li>\n<li>\n<p>We can even utilize a concept which originated from WPF and is called\n<a href=\"https:\/\/docs.microsoft.com\/dotnet\/desktop\/wpf\/advanced\/commanding-overview?view=netframeworkdesktop-4.8\"><em>Command\nBinding<\/em><\/a>.\nIt\u2019s suitable for elements like <code>ToolStripItems<\/code> (and the derived\ncomponents <code>ToolStripButton<\/code>, <code>ToolStripMenuItem<\/code> and others) or\n<code>Button<\/code> controls and implemented via the <code>ICommand<\/code> interface: When the\nuser clicks on such a button in the WinForms UI, and the command property of\nthat button is bound to a respective property in the UI-controller class,\nthe command executes the underlying business code in the business class\nlogic rather than in some <code>Click<\/code> event code-behind.<\/p>\n<\/li>\n<\/ul>\n<p>A UI-controller class would look something like this:<\/p>\n<p><img decoding=\"async\" src=\"https:\/\/devblogs.microsoft.com\/dotnet\/wp-content\/uploads\/sites\/10\/2022\/01\/UiControllerInProject.png\" alt=\"A screenshot of a C# code file in Visual Studio showing a UI controller class implementing INotifyPropertyChanged base class\" \/><\/p>\n<p>Using a combination of data classes (which represent the Database) and\nUI-controller(s) in this way as Object Data Sources has some advantages:<\/p>\n<ul>\n<li>\n<p><strong>Business logic reuse:<\/strong> The business logic is defined by business object\n(data source) classes independently of the UI. This means they can be reused\nin other scenarios. The same business objects which are used in a WinForms\napplication could also be used for example in a Maui .NET mobile\napplication.<\/p>\n<\/li>\n<li>\n<p><strong>Unit tests:<\/strong> Since the business logic doesn\u2019t include any specific\nUI-stack dependencies, it can be unit tested way more easily. That is a big\nadvantage over the WinForms typical code-behind approach.<\/p>\n<\/li>\n<li>\n<p><strong>View model\/UI Controller support:<\/strong> Object Data Source classes can \u2013 or\nrather should \u2013 implement the `INotifyPropertyChanged` Interface. This\nenables data sources to act as UI-Controller classes (or View Models), which\nmake them suitable to be reused in other UI Stacks.<\/p>\n<\/li>\n<\/ul>\n<p><img decoding=\"async\" src=\"https:\/\/devblogs.microsoft.com\/dotnet\/wp-content\/uploads\/sites\/10\/2022\/01\/ModelBindingDiagram.png\" alt=\"A diagram showing the relation between Data\/Model class, UI-controller and a UI Form\" \/><\/p>\n<p>Note: Although the binding infrastructure in WinForms is comparatively powerful,\nit doesn\u2019t have the flexibility of XAML-based binding which you might know from\nWPF, UWP or Maui. For WinForms, you will most likely <em>always<\/em> be ending up with\nsome Code-Behind code to support UI-Controller binding scenarios, which are\notherwise difficult to implement just on the model\/controller side. But that\u2019s\nOK and expected. For a better reusability of code and the ability to write code,\nwhich is testable, it\u2019s still worth the effort. And a migration to this way of\nbinding can be easily done over time, Form by Form, so it is really feasible and\ncan be planned for huge LOB apps. On top, we plan to further support and extend\n<a href=\"https:\/\/github.com\/dotnet\/winforms\/issues\/4895\">UI-controller centric scenarios in the .NET\n7<\/a> time frame for WinForms\nprojects.<\/p>\n<h2>The New <em>Add Object Data Source<\/em> Dialog<\/h2>\n<p>To use a certain class as your Object Data Source, start the binding process as\nyou previously would:<\/p>\n<ul>\n<li>\n<p>Open the Design Binding Picker to add a new Object Data Source definition to\nyour project.<\/p>\n<\/li>\n<li>\n<p>Click on the link <em>Add new Object Data Source<\/em> to find the type you want to\nuse as a data source in your project.<\/p>\n<\/li>\n<li>\n<p>Use the <em>Filter<\/em> field to filter the selection by name. Note that types\nwhich implement the `INotifyPropertyChanged` interface (or derive from\ntypes which are based on that interface) are formatted in bold typeface.<\/p>\n<\/li>\n<li>\n<p>Use the checkboxes in the dialog to include or exclude types, which are not\npart of your project, or to control how the types are organized in the list.<\/p>\n<\/li>\n<\/ul>\n<p>The example in the animated GIF below shows how a slightly modified\n<code>ToolStripMenuItem<\/code> component can be bound this way to a <code>Command<\/code>, and in\naddition a DataGridView\u2019s DataSource to a property of a UI-controller\nrepresenting a list of customers:<\/p>\n<p><img decoding=\"async\" src=\"https:\/\/devblogs.microsoft.com\/dotnet\/wp-content\/uploads\/sites\/10\/2022\/01\/AddNewObjectDataSource.gif\" alt=\"An animated gif showing how to use the Design Binding Picker to access the new Add Object Data Source Dialog\" \/><\/p>\n<p>Here you see that adding <code>MainUIController<\/code> as an Object Data Source and\nthen binding its <code>Import<\/code> command to the <code>ImportExternalDataCommand<\/code>\nproperty automatically led to the adding of the\n<code>mainUiControllerBindingSource<\/code> component: In the Design Binding Picker you\ncan then pick that component as the actual data source.<\/p>\n<h2>History lesson: why BindingSources as mediators and no direct binding?<\/h2>\n<p>Adding a <code>BindingSource<\/code> component for an Object Data Source as a mediator\nbetween the data source and the target control\/component is a concept which\nWinForms adapted from the early beginning (.NET 2.0 back in 2005). The\n<code>BindingSource<\/code> component acts as the so-called <em>currency manager<\/em>. <em>Currency<\/em>\nin this context means, the <code>BindingSource<\/code> component manages which data item\nin a list of items is the <em>current<\/em> one. This way of binding is also done for\nscenarios, for which the data source is or provides only <em>one<\/em> object instance &#8211; a\nUI-controller or a single data source item for a data entry form for example.\nThis principle is being kept for backwards compatibility reasons, which means\nthat any attempt to bind the first property to a newly added (object) data\nsource will <em>always<\/em> add a respective <code>BindingSource<\/code> component to the\ncomponent tray. The actual binding will then be hooked up to that\n<code>BindingSource<\/code> component rather than to the data source directly.<\/p>\n<p><strong>Note:<\/strong> It is important to know in this context, that WinForms doesn\u2019t\nnatively know the concept of type conversion based on the <code>IValueConverter<\/code>\ninterface as it is used in WPF, UWP or WinUI. Rather, a conversion during\nbinding can be done by handling the events, such as <code>Format<\/code> and <code>Parse<\/code>,\nwhich are provided by the actual binding instances generated by the designer for\nthe binding in <code>InitializeComponent<\/code>. Like this:<\/p>\n<pre><code class=\"language-CS\">public FormMain()\r\n{\r\n    InitializeComponent();\r\n\r\n    \/\/ Current version of WinForms Databinding doesn't allow yet\r\n    \/\/ IValueConverter, we do this instead:\r\n    var totalRevenueBinding = _totalRevenueTextBox.DataBindings[0];\r\n\r\n    \/\/ ConvertTo, here Decimal to String as an example:\r\n    totalRevenueBinding.Format += (sender, eventArgs) =&gt;\r\n    {\r\n        if (eventArgs.DesiredType != typeof(string))\r\n        {\r\n            return;\r\n        }\r\n\r\n        eventArgs.Value = ((decimal)eventArgs.Value!).ToString();\r\n    };\r\n    .\r\n    .\r\n    .<\/code><\/pre>\n<p>In this sample code we are assuming there is only one DataSource\/Control binding\nfor a TextBox named <code>_totalRevenueTextBox<\/code>. We\u2019re getting its <code>Binding<\/code>\ndefinition and wire up to its <code>Format<\/code> event, where the actual conversion is\nthen handled at runtime.<\/p>\n<h2>Improvements to Advanced Databinding<\/h2>\n<p>We also made improvements to the Advanced Databinding Editor. You use the\nAdvanced Databinding Editor for all properties which are not listed directly\nunder <em>Data Binding<\/em> in the Property Browser. This dialog now shows what component or\ncontrol you are binding to. It also shows what exact type of that control or\ncomponent you are editing. Also, rather than picking the binding trigger from a\ndrop-down list, you can now directly set that by clicking radio buttons, which\nis quicker and more accessible.<\/p>\n<p><img decoding=\"async\" src=\"https:\/\/devblogs.microsoft.com\/dotnet\/wp-content\/uploads\/sites\/10\/2022\/02\/AdvancedDataBindingEditor.gif\" alt=\"Animated gif showing how to use the Advanced Databinding Editor to bind property paths in complex binding scenarios\" \/><\/p>\n<p>The Advanced Databinding Dialog now allows to set up another binding scenario:\nSometimes it\u2019s necessary that you define a whole property <em>path<\/em> in <em>complex<\/em>\nbinding scenarios \u2013 which are scenarios, where you are binding to a list rather\nthan to a single object instance. In those cases, the correlating\n<code>BindingPath<\/code> and <code>BindingField<\/code> of the Binding\u2019s instance\n<code>BindingMemberInfo<\/code> property can now easily be set in the Advanced Databinding\nEditor by entering the whole path in the <em>Path<\/em> entry field. If this field gets\nthe focus, <em>Path<\/em> and <em>Field<\/em> are merged, and you can edit the property path as\na whole. When that entry field later loses the focus again, <em>Path<\/em> and <em>Field<\/em>\nare separated in the same way as they would show up if you\u2019d queried them at\nruntime through the Binding\u2019s correlating <code>BindingMemberInfo<\/code> property:<\/p>\n<p><img decoding=\"async\" src=\"https:\/\/devblogs.microsoft.com\/dotnet\/wp-content\/uploads\/sites\/10\/2022\/01\/DebuggerBindingMemberInfo.png\" alt=\"A screenshot of a C# code file in VS showing a BindingMemberInfo instance in the Debugger\" \/><\/p>\n<h2>Summary and key takeaways<\/h2>\n<ul>\n<li>\n<p>Databinding in WinForms .NET is focused on Object Data Binding. We encourage\ndevelopers to explore modern ORM technologies like Entity Framework Core,\nwhich can be used in their latest versions <a href=\"https:\/\/docs.microsoft.com\/ef\/core\/miscellaneous\/platforms\">in contrast to .NET\nFramework<\/a>.<\/p>\n<\/li>\n<li>\n<p>Databinding of legacy technologies (Typed DataSets) is still supported,\nalbeit with some limitations. Typed DataSet definitions can be copied from\nFramework projects, but new Typed DataSets cannot be created in .NET\nprojects, nor can their schemas interactively be changed.<br \/>\n<strong>Tip<\/strong>: Old and new database mapping technologies can coexist in a WinForms project,\nso there is a <em>feasible<\/em> way to gradually migrate the underlying data layer\ntechnologies, one Form at a time.<\/p>\n<\/li>\n<li>\n<p>Object Data Sources are defined for the project through the <em>Design Binding\nPicker<\/em> in the Property Browser by clicking on the <em>Add New Object Data\nSource<\/em> link. The Data Source Provider Service is at the time not available\nfor .NET projects (neither WinForms nor WPF). That is also the case for the\nData Sources tool window, which relies on the Data Source Provider Service.<\/p>\n<\/li>\n<li>\n<p>Object Data Sources are a great tool migrating business \u201cCode-behind\u201d logic\nfrom Forms and UserControls into UI-stack-independent controller classes.\nThis way, it becomes easier for WinForms apps to be unit tested or reuse\nbusiness logic code in other contexts, and also have a clear migration path\nto introduce modern technologies in WinForms LOB Apps.<\/p>\n<\/li>\n<li>\n<p>The Advanced Databinding Dialog is now easier to handle and more accessible.\nIt now also allows the definition for entering property paths for complex\nbinding scenarios.<\/p>\n<\/li>\n<\/ul>\n<p>As always, please tell us which features you would like to see in the Designer\nbut also in the WinForms runtime around the databinding area.<\/p>\n<p>Happy WinForms Coding!<\/p>\n","protected":false},"excerpt":{"rendered":"<p>Databinding in the Windows Forms OOP Designer focuses on Object Data Sources, and it has a different approach to set up data sources compared to the .NET Framework Designer. Read what you need to know about Databinding in WinForms for .NET apps.<\/p>\n","protected":false},"author":9483,"featured_media":38579,"comment_status":"open","ping_status":"closed","sticky":false,"template":"","format":"standard","meta":{"_acf_changed":false,"footnotes":""},"categories":[685,195,7163],"tags":[7342,7221],"class_list":["post-38578","post","type-post","status-publish","format-standard","has-post-thumbnail","hentry","category-dotnet","category-dotnet-framework","category-winforms","tag-designer","tag-windows-forms"],"acf":[],"blog_post_summary":"<p>Databinding in the Windows Forms OOP Designer focuses on Object Data Sources, and it has a different approach to set up data sources compared to the .NET Framework Designer. Read what you need to know about Databinding in WinForms for .NET apps.<\/p>\n","_links":{"self":[{"href":"https:\/\/devblogs.microsoft.com\/dotnet\/wp-json\/wp\/v2\/posts\/38578","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=38578"}],"version-history":[{"count":0,"href":"https:\/\/devblogs.microsoft.com\/dotnet\/wp-json\/wp\/v2\/posts\/38578\/revisions"}],"wp:featuredmedia":[{"embeddable":true,"href":"https:\/\/devblogs.microsoft.com\/dotnet\/wp-json\/wp\/v2\/media\/38579"}],"wp:attachment":[{"href":"https:\/\/devblogs.microsoft.com\/dotnet\/wp-json\/wp\/v2\/media?parent=38578"}],"wp:term":[{"taxonomy":"category","embeddable":true,"href":"https:\/\/devblogs.microsoft.com\/dotnet\/wp-json\/wp\/v2\/categories?post=38578"},{"taxonomy":"post_tag","embeddable":true,"href":"https:\/\/devblogs.microsoft.com\/dotnet\/wp-json\/wp\/v2\/tags?post=38578"}],"curies":[{"name":"wp","href":"https:\/\/api.w.org\/{rel}","templated":true}]}}