The .NET 2.0 provides System.Web.UI.WebControls.BaseDataBoundControl and DataBoundControl classes that can be useful for Custom Data-Bound Web Server Controls . However it often convinient to have User Control with similar data-binding capabilities.
Unfortunetely .Net doesn’t allow multiple inheritance, so I have to duplicate the functionality in my DataBoundUserControl class derived from UserControl class.
At the moment the DataBoundUserControl class is not fully implemented.As it explained in “Data Source Controls – Under the Hood” , data-bound control has to use a wrapper class in order to expose the DataSource as a data source control (ReadOnlyDataSource that implements IDataSource, returning a view (ReadOnlyDataSourceView) that only supports the select method). MS made ReadOnlyDataSource and ReadOnlyDataSourceView not public, so we need to re-invent them if needed.
As a shortcut derived User Controls should overide PerformSelectDataBinding() method.
Imports Microsoft.VisualBasic
Imports System.ComponentModel
‘Based on http://msdn2.microsoft.com/en-us/library/ms366539.aspx article “Developing Custom Data-Bound Web Server Controls for ASP.NET 2.0”
Public Class DataBoundUserControl
Inherits System.Web.UI.UserControl
True), DefaultValue(CStr(Nothing))> _
Public Overridable Property DataSource() As Object
‘from http://msdn2.microsoft.com/en-us/library/system.web.ui.webcontrols.basedataboundcontrol.datasource.aspx
‘ When you set the DataSource property, the ValidateDataSource method is called. In addition, if the data-bound control has already been initialized, the OnDataPropertyChanged method is called to set the RequiresDataBinding property to true.
Get
Return m_dataSource
End Get
Set(ByVal value As Object)
If (Not value Is Nothing) Then
ValidateDataSource(value)
End If
m_dataSource = value
OnDataPropertyChanged()
End Set
End Property
Private m_dataSource As Object
Public Overridable Property DataSourceID() As String
Get
Dim o As Object = ViewState(“DataSourceID”)
If (Not o Is Nothing) Then
Return CStr(o)
End If
Return String.Empty
End Get
Set(ByVal value As String)
ViewState.Item(“DataSourceID”) = value
OnDataPropertyChanged()
End Set
End Property
Protected Property RequiresDataBinding() As Boolean
Get
Return m_requiresDataBinding
End Get
Set(ByVal value As Boolean)
m_requiresDataBinding = value
If (m_preRendered AndAlso m_requiresDataBinding = True) Then
Me.EnsureDataBound()
Else
End If
End Set
End Property
Private m_requiresDataBinding As Boolean
Protected Overridable Sub ValidateDataSource( _
ByVal dataSource As Object _
)
‘from ms-help://MS.VSCC.v80/MS.MSDN.v80/MS.NETDEVFX.v20.en/cpref16/html/M_System_Web_UI_WebControls_DataBoundControl_ValidateDataSource_1_b4c5a2da.htm
‘The DataBoundControl class checks the type of the object that is set for the DataSource property to ensure that it is an instance of the IDataSource, IListSource, or IEnumerable interface.
If (((Not dataSource Is Nothing) AndAlso Not TypeOf dataSource Is IListSource) AndAlso (Not TypeOf dataSource Is IEnumerable AndAlso Not TypeOf dataSource Is IDataSource)) Then
Throw New InvalidOperationException(“DataBoundControl Invalid DataSource Type” & dataSource.GetType.ToString())
End If
End Sub
Protected Overridable Sub OnDataPropertyChanged()
RequiresDataBinding = True
End Sub
‘Calls the DataBind method if the DataSourceID property is set and the data-bound control is marked to require binding.
‘Does nothing if DataSource is used
‘The EnsureDataBound method is called during the OnPreRender method, to call the DataBind method if the data-bound control is not yet bound.
‘The EnsureDataBound method might also be called during calls to CreateChildControls and LoadPostData methods.(?? -not tested yet)
Protected Overridable Sub EnsureDataBound()
If (RequiresDataBinding And IsBoundUsingDataSourceID()) Then
Me.DataBind()
End If
End Sub
‘Overrides the Control.OnPreRender event handler to call EnsureDataBound before calling the base class OnPreRender method.
‘invokes data-binding logic as late as possible during the page life cycle and only when needed
Protected Overrides Sub OnPreRender(ByVal e As EventArgs)
m_preRendered = True
EnsureDataBound()
MyBase.OnPreRender(e)
m_preRendered = False
End Sub
Private m_preRendered As Boolean = False
Protected ReadOnly Property IsBoundUsingDataSourceID() As Boolean
Get
Return (DataSourceID.Length > 0)
End Get
End Property
Public Overrides Sub DataBind()
PerformSelect()
End Sub
Protected Sub MarkAsDataBound()
ViewState(“DataBound”) = True
End Sub
Protected Overridable Sub PerformSelect()
‘ Call OnDataBinding here if bound to a data source using the DataSource property (instead of a DataSourceID) because the
‘ data-binding statement is evaluated before the call to GetData.
If Not IsBoundUsingDataSourceID Then
OnDataBinding(EventArgs.Empty)
End If
PerformSelectDataBinding()
‘ The PerformDataBinding method has completed.
RequiresDataBinding = False
MarkAsDataBound()
‘ Raise the DataBound event.
‘Not implemented yet OnDataBound(EventArgs.Empty)
End Sub ‘PerformSelect
Protected Overridable Sub PerformSelectDataBinding()
Throw New NotImplementedException(” should be overridde in derived class”)
” The GetData method retrieves the DataSourceView object from the
” IDataSource associated with the data-bound control.
‘TODO according to http://www.manuelabadia.com/blog/PermaLink,guid,678ed6d8-dce8-40d7-9117-0ffd016fe886.aspx
‘it has to use a wrapper class in order to expose the DataSource as a data source control (ReadOnlyDataSource that implements IDataSource, returning a view (ReadOnlyDataSourceView) that only supports the select method).
‘Unfortunately, MS made ReadOnlyDataSource and ReadOnlyDataSourceView not public, so we need to re-crete them if needed
‘GetData().Select(CreateDataSourceSelectArguments(), AddressOf OnDataSourceViewSelectCallback)
End Sub ‘PerformSelect
End Class