Introduction
The current version 2.0 of the ASP.NET Framework has several rich data controls like GridView
. It works optimally when bound using the DataSourceID
parameter. The rich controls work well if directly connected to SQL database using SqlDataSource
object. Similar services should provide the binding tool ObjectDataSource
for binding to data in memory, for business objects.
The author tried binding using the ObjectDataSource
tool. The main parameter of the tool defines only type of bound object - its temporary instance is created either only during the binding operation, or the operations are provided by static
functions of the type without creating an object at all. The author met with significant problems in realization of interaction between those temporary objects and/or static
functions and other objects on the Web page, particularly when the final data source is some generic collection like generic List<...>
; better results give binding of classical DataTable
. Notwithstanding that, rich functionality of the DataTable
provides for changed rows of both old and modified data.
Background
Instead of creating a particular data structure and converting some collection of business objects into a generic collection, it can be transformed to classical .NET data structure DataTable
. When bound to rich controls, DataTable
ensures their maximal functionality without writing complicated user code. The result of such reflection was the idea of a simple data binding element between the rich control and the table; the user would update data through the controls and the program would finally transform changes stored in DataTable
to real data objects. Naturally, it would be optimal, if business data would be stored directly in DataTable
s or its collection - DataSet
, possibly including their relations - or structures, where data conversion is simple.
The author's conception of the use of the described control is in filling the data table, its update by the user, and finally resolution (using corresponding buttons) to COMMIT
data changes (i.e. save changes in business objects and calling DataTable.AcceptChanges()
) or ignore them (calling DataTable.RejectChanges()
). Or more generally: custom data source control or simply *.aspx page can initially transfer data from a business object collection to the table, then perform its update using rich data control, and finally either transfer data back to the business object collection (e.g. selecting button COMMIT
or APPLY
), or rollback all changes (e.g. selecting button IGNORE
).
The entire project was based on an example from the MSDN library - class CsvDataSource
and Web presentation (and user comments) of Nikhil Kothari referred to below.
Naturally, realization of such ideas often result in more complicated software than was originally seen. The presented project illustrates two approaches:
- Editing data directly in one
GridView
control bound using TableDataSource
editing its columns directly (TestTableDataSource.aspx).
- Selecting data rows in
GridView
and their editing in DetailsView
control using two TableDataSource
s binding a single table to two controls (TestTableMasterDetail.aspx).
The presented example is based on our specific conditions, where each table has one integer identity column as key; it can be simply adapted for a more general case. It is based on simple logic, which can be well understood; the author is not a specialist in the field. Reasonable comments and improvements are welcome.
The example project is started using the solution WEB.sln. It consists of two projects: control library project creating library TableDataSource.dll and own Web site (two pages) in folder WEB.
Basic Components
The presented example consists of these basic components:
- Class
TableDataSource
based on system class System.Web.UI.DataSourceControl
realizing basic functionality - Complementary class
TableDataSourceView
based on the complementary base class System.Web.UI.DataSourceView
realizing own data binding returned from TableDataSource
to bound control - Two Web pages TestTableDataSource.aspx and TestTableMasterDetail.aspx realizing updating of data in the bound table both directly in
GridView
and master-detail schema of related GridView
and DetailsView
. Both DataGrid
s naturally enable paging and column sorting, which require practically no additional code. - Auxiliary
enum
type Gender
illustrating use of user defined classes and template columns in rich controls - Auxiliary generic
static
function BindEnum<T>()
for binding of DropDownList
s to enum
data types. Helper class Util
helps to bypass limitations of the C# language.
The last two components are presented as part of the source file TableDataSource.cs which also contain the source of the two basic classes of user component TableDataSource
.
Class TableDataSource
This class declares these basic elements:
- Default constructor
- Property
Table
of type DataTable
is generally set from the external program and stores reference to DataTable
object. When setting this property, objects bind to events with corresponding changes in Table
object. - Property
RowFilter
of type string
. This string
represents constant part of row selection filter, while the variable part is determined by the next parameter. While set
ting the property assigns only its constant part, upon get
it returns full WHILE
query condition. - Parameter collection
<SelectParameters>
of individual parameters; each parameter defines one condition in the form ident = value
; all conditions including possible RowFilter
are connected by logical operator AND
. Parameter collection can be edited using property window by standard parameter collection editor. - Method
DataSourceView GetView(string viewName)
realizes own data binding returning instance of the class DataSourceView
to bound rich data control. - Internal
int
property InsertedKey
is helper to set temporary unique negative keys for inserted columns; final value is set later during final insertion. Private
event handler tableDataChanged(object source, EventArgs e)
transferring table change events to base class by calling its function RaiseDataSourceChangedEvent(e).
Class TableDataSourceView
This class is used internally from the base class and declares these basic elements:
- Constructor
public TableDataSourceView(IDataSource owner, string name)
analogous to the base class. Owner is the corresponding TableDataSource
object, name is derived from its ID and is used mainly for debugging. - Binding requires property
public static string DefaultViewName = "TableSourceView"
. - Overridden virtual function
System.Collections.IEnumerable ExecuteSelect(DataSourceSelectArguments arguments)
realizes own data transfer to rich control. Returns DataView
derived from bound table with supplied sort expression from arguments and RowFilter
derived from properties of view owner. - Overridden virtual function
ExecuteUpdate(System.Collections.IDictionary keys, System.Collections.IDictionary values, System.Collections.IDictionary oldValues)
realizing update of one data row. - Overridden virtual function
ExecuteDelete(System.Collections.IDictionary keys, System.Collections.IDictionary oldValues)
realizing deleting of one data row. - Overridden virtual function
ExecuteInsert(System.Collections.IDictionary values)
realizing insertion of one data row.
Conclusion
Presented data control is only a primitive realization of concept being much better realized in standard .NET data source controls. It demonstrates basic principles, while details can be supplemented according to first experiences.
The author appreciates any reader comments and advice for improving the presented material.
Correction
- After finishing, I found some improvements enabling automatic rebind after change of
RowFilter
- it is tested in OnPreRender
and then control notifies bound elements. - I thank Ebrahimhassan for his valuable discussion. I found some bugs caused by incorrect management of
null
and DBNull
values - I believe that now it works better. - The functionality of the presented example is limited to conditions and rules applied in my environment: All tables have unique primary keys with single numeric values - more general case is left to readers. The main reason of my example is presenting principles, not final solutions.
- New version lets in the Master - Detail model inserted row open for editing - it illustrates a new generation of
PageIndex
and SelectedIndex
in the bound grid. - Open source control has one significant advantage - its user can set breakpoints to its key points (e.g.
ExecuteSelect
, ExecuteUpdate
... in the presented example) and study behavior of developed code. It can be used as a valuable debugging tool.
History
- 11th March, 2007 - Initial version
- 13th March, 2007 - Corrected, completed, new references
- 20th June, 2007 - Revised, bug removal
References
I'm 63 years old, originally physicist, later programmer by profession, now pensioner.
Jirí Šoler