Generated code - Databinding with Windows Forms and ASP.NET 1.x, Adapter

Preface

Databinding is a .NET feature which can drastically increase productivity when it is implemented correctly. It is also a technique that works both with single objects and properties as well with collections with objects. To be able to use databinding with the generated code, both the entity objects and the entity collections are made databinding aware. This section describes the databinding functionality addressed in the generated code and also the design time functionality available to you for windows forms applications and ASP.NET 1.x applications.

As there are big difference between the databinding mechanism implemented in .NET 1.x and .NET 2.0, some paragraphs are for a specific .NET version.

Implemented functionality

This section briefly discusses the implemented functionality in the various classes of the generated code you will use with databinding.

.NET 1.x specific: functionality implemented in Entity classes
In the .NET 1.x code, entity classes are equipped with field nameChanged events, which are necessary for databinding. This means that if you bind a property of an entity object to a textbox in your GUI, the textbox is automatically updated when the entity's field's value is changed using other code than the textbox. Entity classes furthermore implement ICustomTypeDescriptor. Every entity implements IEditableObject.

.NET 2.0 specific: functionality implemented in Entity classes
In the .NET 2.0 code, entity classes don't have the fieldChanged events, they implement the new .NET 2.0 interface INotifyPropertyChanged. This interface replaces the .NET 1.x events which were necessary for databinding. The interface INotifyPropertyChanged serves the same purpose: when a property changes, it raises an event and bound controls can update themselves if they're interested. This means that if you bind a property of an entity object to a textbox in your GUI, the textbox is automatically updated when the entity's field's value is changed using other code than the textbox. Every entity implements IEditableObject.

Typed views and typed lists
Typed View and Typed List objects are generated as classes deriving from DataTable, and because the DataTable already is equipped with all the databinding functionality necessary, you can bind a Typed View or Typed List without trouble to a datagrid or to a set of GUI controls.

EntityCollection instances
The EntityCollection class (generic and non-generic) in LLBLGen Pro implement the IListSource interface. This means that bound controls will request from the interface an object they can bind to. Every entity collection returns its DefaultView when this request comes. This thus means that when you set a control's DataSource property to an entity collection instance, the collection won't bind directly to the control though it will bind to the control through its DefaultView.

This also means that if you create your own EntityView2 instance on a given entity collection, you can bind that EntityView2 to the control instead, to have a subset of the data in an entity collection visible in the control. This is similar to how DataTable and DataView work hand in hand. All actions taken on the data, including creating new entities in a grid for example, are performed on the entity collection. When you're using your own EntityView2 instance, be sure to set the DataChangeAction property of the EntityView2 instance to the correct value. For details, please see: Generated code - using the EntityView2 class for details.

When an entity has 1:m or m:n relations with other entities, it will expose properties which in turn will return an EntityCollection (non-generic in .NET 1.x, generic in .NET 2.0). For example the customer entity has an 'Orders' property which returns a collection of OrderEntity objects. These collection properties are shown in the DataGrid when AllowNavigation is set to true and when you click open the [+] in front of the entity row. You can then click on one of the collection returning properties and the grid will be filled with the entity rows of that collection. This way you can browse a complete object model, just by walking relations. Adapter doesn't read data 'on the fly', but requires you to read data up-front to avoid ties with database-interaction code in tiers. Therefore if you want to traverse data in a datagrid, you need to fetch this data up-front prior to binding the EntityCollection to the grid, for example by using Prefetch Paths.

EntityView2 implements all useful properties and methods of IBindingList. Among these features are: sorting in grids, making the EntityView2 read-only, do not allow addition, removal of rows.

Table styles and mapping names
When you want to setup table styles in grids, you've to specify the name of the bound object in the MappingName property of the table style. The following rule is used for this mapping name when you bind an entity collection to a grid:
The list name of an entitycollection bound to a grid is constructed from the following parts: the LLBLGenProEntityName of an instance created by the factory set for the collection + "Collection". So if the entity factory is set to CustomerEntityFactory, the name is "CustomerEntityCollection".

Design time support in VS.NET 2002/2003

The generated code supports design time databinding out of the box for the EntityCollection, typed views and typed lists and all derived classes, in .NET 1.x and .NET 2.0. To use design time databinding, open a form (which can be a webform or a windows forms form) in design mode and open the toolbox in your IDE (for example Visual Studio.NET). Select the tab for My Controls and select Add/Remove Items.... In the dialog, select Browse... and select the compiled assembly of the generated code. As soon as the IDE (for example Visual Studio.NET) has investigated which components are available in the selected assembly, it will check and select all of them available (which will be EntityCollection, all typed views and all typed lists). Make sure the selection meets your needs and click OK, which will add all the selected components to the toolbox.

You can now select one of the components and drag it onto the form, for example the EntityCollection class. The IDE will place the collection instance in the component area for the form, which is normally at the bottom of the screen. As soon as you drag an EntityCollection class onto your form, a designer will pop up with all IEntityFactory2 implementing classes in the generated code. For example, if the generated code is for Northwind, you can select the CustomerEntityFactory. As soon as you've selected the factory you want, the EntityCollection instance in the component area of the form will be able to produce property descriptors and you will be able to select it as the proper datasource for a grid on your form. If you want to check which EntityFactory is currently set in the EntityCollection instance, click it and view the properties window in the IDE, which will show you, among other properties, the EntityFactoryName property. To set it to another EntityFactory, click the EntityCollection instance with the right mouse button and select "Set EntityFactory to use" from the context menu, which will bring up the designer again. To reflect the columns in the grid, first select 'None' as DataSource and then re-select the EntityCollection instance as the DataSource value.

If you have a grid control located on the form, you can select its DataSource property and set it to the component you've dragged onto the form. When you're designing a windows forms form, you can also select the DataMember value. For example if you've selected the CustomerEntityFactory as the factory to use, the EntityCollection will contain CustomerEntity instances, which contain an EntityCollection for Employees, for Orders etc. which'll show up in the DataMember list.

Using this feature, you can rapidly setup gui's which are bound to classes in the generated code. Because the design time databinding will create an instance of the class dragged onto the form, for example EntityCollection, which instance will have a valid instance of the factory you've set at design time, for example CustomerEntityFactory, you only have to add the calls to the DataAccessAdapter.FetchEntityCollection method to fill the form with data at runtime.

Design time support in VS.NET 2005

In VS.NET 2005, design time databinding for Windows forms works as described above in the previous section, Design time support in VS.NET 2002/2003, however some things are made easier for you. VS.NET 2005 will automatically find the generated, non-generic EntityCollection class in your project's generated code as well as the typedlists and typed views. If you don't get the EntityCollection class in your toolbox, please follow the procedure of the previous section to add them to the toolbox. It's important to use the generated EntityCollection class for design time databinding, as design time databinding in VS.NET 2005 doesn't support generics, which means that you can't add the EntityCollection(Of TEntity) from the ORMSupportClasses to the toolbox and drag that class onto a form.

In VS.NET 2005, you can still directly bind an EntityCollection to a grid control, but it's recommended to use a BindingSource control, which is new in .NET 2.0. To setup a .NET 2.0 DataGridView control, not only drag the EntityCollection onto your form but also a BindingSource control. You then set the DataGridView's DataSource property to the BindingSource control and the BindingSource' DataSource property to the EntityCollection dragged onto the form. The EntityCollection class then doesn't have a factory set so use the the smart-tag on the EntityCollection on the form to configure the collection which will show the EntityCollection's designer. After you've selected the factory to use, you should see the DataGridView setup with the columns of the entity type contained in the bound EntityCollection.

ASP.NET got a completely different databinding framework in .NET 2.0 and it requires a different approach. To read more about ASP.NET 2.0 databinding at design time and runtime, please see: Generated code - Databinding with ASP.NET 2.0

Databinding and inheritance

When using an inheritance hierarchy, you typically have subtypes with more fields than the supertypes. As LLBLGen Pro supports polymorphic fetches, it can be in an entity collection, entities of various types (all from the same inheritance hierarchy) are found. If several of these entity types have fields not found in their supertypes or siblings in the hierarchy, what will show up in a grid if such a collection is bound to that grid?

LLBLGen Pro will provide to the bound control properties for all fields which are found in the type set for the collection. For example, if you've a hierarchy like Employee <- Manager <- BoardMember, and you fetch all Manager entities into an EntityCollection with ManagerEntityFactory set as its factory. It then can be that one or more of the Manager entities in the collection are actually of type BoardMember, due to Polymorphic Fetching. BoardMember entities have for example a field called CompanyCarId, and Manager entities don't have that field. Binding the fetched EntityCollection to a grid, only the fields from the Manager entity will show up in the grid, as that's the type set for the EntityCollection bound, due to the set ManagerEntityFactory.

You could argue to show 'null' for fields not in Manager but in subtypes, however what if two types derived from Manager, both having a different set of new fields not present in the Manager entity? It would be unclear when a user should fill in a field or not, as for each field a column would be created in the case when all fields in all types in the collection are shown in the grid. Hence, the display of solely the fields of the type set for the collection.

LLBLGen Pro v2.6 documentation. ©2002-2008 Solutions Design