In a previous article I explained the infrastructure for a data bound control (how it gets data from a DataSourceView and when the framework calls the DataBind method). Now it’s time to explain a bit the DataSourceControl class.
The only good information I’ve found about this is a series of articles by Nikhil Kothari, an ASP.NET team member:
If you haven’t read his book Developing Microsoft ASP.NET Server Controls and Components, buy it, read it, and then continue reading this article. It’s the best ASP.NET book out there (even if it’s for ASP.NET 1.x).
If you want to use the new data binding infrastructure with data bound controls, you must have your data source to implement IDataSource, or use one of the data source controls that ASP.NET 2.0 ships with (SqlDataSource and ObjectDataSource).
To help implementing custom data sources, you can inherit from DataSourceControl, because this class makes your life easier. The DataSourceControl class inherits from Control and implements the IDataSource and IListSource interfaces. Let’s examine those interfaces and look at the implementation of DataSourceControl.
The IDataSource interface is very small, it only has the following public methods:
DataSourceView GetView(string viewName);
The first method obtains a particular view and the second method gives information about how many DataSourceViews exposes and what are their names. Both DataSourceControls (SqlDataSource and ObjectDataSource) have only one view, but you may find useful to have more than one view to expose part of the data source in another way.
In a data bound control, you select the DataSourceControl to use setting the DataSourceId property. If you have multiple views, you have to set the DataMember property to tell the control which view you want to bind to. If you don’t set this property, a data bound control will call GetView(null) that should return the default view.
If you remember my previous article, DataBoundControl has a method called ConnectToDataSourceView, that tries to find a DataSourceView from the data source (easily done using the IDataSource interface). However, to support the old binding infrastructure, a DataSourceControl also has a DataSource property that can be set to an object doesn’t implement IDataSource, so to make things orthogonal , DataBoundControl used a read only DataSourceControl wrapper that exposes the data as a read only DataSourceView in that case.
The IDataSource interface also exposes a public event:
event EventHandler DataSourceChanged;
As I explained in my previous article, a DataBoundControl captures the DataSourceView's DataSourceViewChanged event if the control is bound to a DataSourceControl. When the data source changes, this event is fired and DataBoundControl calls DataBind to get fresh data. If the DataSourceControl is changed, it will fire the DataSourceChanged event that all DataSourceViews should capture to update their data (the implementation of the DataSourceView class caputres this event and fires a DataSourceViewChanged event).
DataSourceControl implements the IDataSource interface but the implementation does nothing, because it calls the template methods GetView and GetViewNames that should be implemented by the subclasses.
The IListSource interface lets an object to return a list that can be bound to a data source. Why does DataSourceControl implement IListSource? To let you bind a DataSourceControl to the DataSource property of a control that doesn’t inherit from BaseDataBoundControl, such as the DataGrid.
DataSourceControl implementation of the IListSource interface simply calls to the ListSourceHelper class. This class will expose a list of views (DataSourceViews) to bind to (similar to what the DataSet does with its DataTables). This list of views implements the ITypedList interface to expose the schema for binding. I won’t go into details of ITypedList but if you’re interested you can read more about it here:
To make a long story short, the implementation of IListSource in DataSourceControl exposes a list of views, an each view is presented as a ReadOnly property of type IEnumerable, whose value is retrieved using the view’s ExecuteSelect method.
The rest of the DataSourceControl class only hides some properties from the Designer because a DataSourceControl inherits from Control, but it doesn’t want to behave as a Control. It isn’t a component either because Components in ASP.NET 2.0 are useless. As DataSourceControl may need to interact with the Page’s life cycle it should be implemented as a control but doesn’t want all the capabilities of a control. This is an inconsistency in ASP.NET. I think they should bring to life components in ASP.NET 2.0 and give an option for a component to take part in the life cycle.
That’s it for the DataSourceControl class. In a future post I’ll talk about DataSourceView, which is really the important class in the data binding infrastructure.