Introduction
This article describes how to provide design-time databinding functionality to a custom web control when it is used in a data bound composite control's template. An example of this would be if you added your custom web control to an asp:Repeater
's ItemTemplate
.
Background
When a custom web control is used inside of a databound composite control's template, the custom web control's designer is not used at design-time and databound properties are not set even though the Databind
event is called. In order to set the custom web controls databound properties to correctly display the control at design time, a DataBindingHandler
must be used.
Using the code
Shown below is sample code for a generic DataBinderHandler
. This handler should correctly display any Bind("PropertName")
, Eval("PropertyName")
, or DataBinder.Eval(Container,"PropertyName")
expression at design time.
In order to tell the designer to use a DataBinderHandler
, you must add the DataBindingHandler
attribute to the custom web control.
<Designer(GetType(InvoiceControlDesigner)), _
DataBindingHandler(GetType(DEDataBindingHandler)), _
ToolboxData("<{0}:InvoiceControl runat="server"></{0}:InvoiceControl>")> _
Public Class InvoiceControl
Inherits System.Web.UI.WebControls.CompositeControl
.....
End Class
Public Overrides Sub DataBindControl(ByVal designerHost As _
System.ComponentModel.Design.IDesignerHost, _
ByVal control As System.Web.UI.Control)
Dim myIDataBindingAccesor As IDataBindingsAccessor = control
If myIDataBindingAccesor.HasDataBindings Then
For Each mydatabinding As DataBinding In _
myIDataBindingAccesor.DataBindings
Dim pinfo As System.Reflection.PropertyInfo
pinfo = control.GetType.GetProperty(mydatabinding.PropertyName, _
mydatabinding.PropertyType, System.Type.EmptyTypes)
If pinfo IsNot Nothing Then
Dim MyValue As Object = Nothing
Select Case mydatabinding.PropertyType.FullName
Case "System.String"
MyValue = "ABC"
Case "System.Date"
MyValue = #1/1/1970#
Case "System.Integer", "System.Long"
MyValue = 123
Case "System.Single", "System.Double"
MyValue = 12.34
Case Else
MyValue = "DataBound"
End Select
Try
If control.BindingContainer IsNot Nothing AndAlso _
TypeOf control.BindingContainer Is IDataItemContainer Then
If mydatabinding.Expression.ToLower.StartsWith("bind(""") Or _
mydatabinding.Expression.ToLower.StartsWith("eval(""") Or _
mydatabinding.Expression.ToLower.StartsWith("databinder.eval(container") Then
Dim StartPosition As Integer = mydatabinding.Expression.IndexOf("(")
Dim FormatPosition As Integer
Dim ExPrefix As String = ""
If Not mydatabinding.Expression.ToLower.StartsWith(_
"databinder.eval(container") Then
ExPrefix = "DataItem."
Else
StartPosition = mydatabinding.Expression.IndexOf(",", StartPosition) + 2
End If
FormatPosition = mydatabinding.Expression.IndexOf(",", StartPosition)
Dim mydatabindingex As String = ""
If FormatPosition > 4 Then
mydatabindingex = mydatabinding.Expression.Substring(StartPosition, _
FormatPosition - StartPosition + 1)
Dim FormatString As String
FormatString = mydatabinding.Expression.Substring(FormatPosition + 2, _
mydatabinding.Expression.Length - FormatPosition - 4)
MyValue = DataBinder.Eval(control.BindingContainer, _
ExPrefix & mydatabindingex, FormatString)
Else
mydatabindingex = mydatabinding.Expression.Substring(StartPosition, _
mydatabinding.Expression.Length - StartPosition - 2)
MyValue = DataBinder.Eval(control.BindingContainer, _
ExPrefix & mydatabindingex)
End If
End If
End If
Catch ex As Exception
Debug.WriteLine("DataBinderHandler Failed " & ex.ToString)
End Try
If System.Type.Equals(MyValue.GetType, mydatabinding.PropertyType) Then
pinfo.SetValue(control, MyValue, Nothing)
End If
End If
Next
End If
End Sub
End Class
The ASP.NET code:
<asp:Repeater ID="Repeater1" runat="server"
DataMember="InvoiceList" DataSourceID="DEDataSource1">
<ItemTemplate>
<asp:Label ID="Label1" runat="server"
Text='<%# Bind("InvoiceID") %>'></asp:Label>
<DE:InvoiceControl ID="InvoiceControl1" runat="server"
Invoice='<%# Databinder.Eval(Container,"DataItem") %>'
LogoImagePath="http://www.digitalexample.com/images/delogo.gif"
InvoiceControlMode="ReadOnly" InvoiceControlStyle="Default" >
<InvoiceTableStyle CellPadding="3"
CellSpacing="0" Height="100%" Width="100%" />
</DE:InvoiceControl>
Points of interest
It took a lot of digging before I was able to figure out why my custom control would not work once placed inside of a Repeater
. Debugging revealed that the databound properties were not getting set but the databinding event was getting called. I also noted that at design time, the designer did not call the PreRender
event. I am not sure why Microsoft did not include a generic DataBindingHandler
to be used when there was not a DataBindingHandler
attribute set.
History
- Originally posted on 08/21/2007 by Andrew DeVries.