В проекте возникла проблема: имеется куча бизнес-объектов, которые необходимо как-то отображать/редактировать/обновлять/добавлять. Возник вопрос как лучше всего организовать web-приложение в этом случае, чтобы писать по минимуму рутинного кода для привязки объекта к контролам.
Все решилось просто, главная идея - чтобы идентификаторы контролов совпадали с названиями свойств.
Наш тестовый бизнес-объект:
Public Class TestBusinessObject
Private _id As String
Private _name As String
Private _city As String
Private _hasSomething As Boolean
Public Property Id() As String
Get
Return _id
End Get
Set(ByVal Value As String)
_id = Value
End Set
End Property
Public Property Name() As String
Get
Return _name
End Get
Set(ByVal Value As String)
_name = Value
End Set
End Property
Public Property City() As String
Get
Return _city
End Get
Set(ByVal Value As String)
_city = Value
End Set
End Property
Public Property HasSomething() As Boolean
Get
Return _hasSomething
End Get
Set(ByVal Value As Boolean)
_hasSomething = Value
End Set
End Property
End Class
Наш класс-помощник в деле binding’a (привязки данных):
Imports System.Reflection
Public Class BindingHelper
#Region "Binding object to controls"
'''
''' This will bind object properties to control values
'''
''' Object
''' Container (page usually)
''' Prefix of control name (this will be used if you need to bind several controls to the same page)
Public Shared Sub BindObjectToControls(ByVal obj As Object, ByVal container As Control, ByVal propertyNamePrefix As String)
'check object for nothing
If obj Is Nothing Then
Return
End If
'loop all obj properties
For Each objProperty As PropertyInfo In obj.GetType.GetProperties()
'look for control with specified property name
Dim control As control = container.FindControl(propertyNamePrefix & objProperty.Name)
If Not (control Is Nothing) Then
SetPropertyValueToControl(control, objProperty.GetValue(obj, Nothing))
End If
Next
End Sub
'''
''' This will bind object properties to control values
'''
''' Object
''' Container (page usually)
Public Shared Sub BindObjectToControls(ByVal obj As Object, ByVal container As Control)
BindObjectToControls(obj, container, String.Empty)
End Sub
'Bind property value to control
Private Shared Sub SetPropertyValueToControl(ByVal control As Control, ByVal value As Object)
If TypeOf control Is TextBox Then
'process text box
CType(control, TextBox).Text = value
ElseIf TypeOf control Is DropDownList Then
'process DropDownList
Dim ddList As DropDownList = CType(control, DropDownList)
Dim item As ListItem = ddList.Items.FindByValue(value)
If item Is Nothing Then
ddList.SelectedIndex = 0
Else
ddList.SelectedIndex = ddList.Items.IndexOf(item)
End If
ElseIf TypeOf control Is CheckBox Then
'process CheckBox
CType(control, CheckBox).Checked = value
ElseIf TypeOf control Is HtmlInputHidden Then
'process HtmlInputHidden
CType(control, HtmlInputHidden).Value = value
End If
End Sub
#End Region
#Region "Binding controls to object"
'''
''' This will bind control values to object properties
'''
''' Object
''' Container (page usually)
''' Prefix of control name (this will be used if you need to bind several controls to the same page)
Public Shared Sub BindControlsToObject(ByVal obj As Object, ByVal container As Control, ByVal propertyNamePrefix As String)
'check object for nothing
If obj Is Nothing Then
Return
End If
'loop all obj properties
For Each objProperty As PropertyInfo In obj.GetType.GetProperties()
'look for control with specified property name
Dim control As control = container.FindControl(propertyNamePrefix & objProperty.Name)
If Not (control Is Nothing) Then
objProperty.SetValue(obj, GetControlValue(control), Nothing)
End If
Next
End Sub
'''
''' This will bind control values to object properties
'''
''' Object
''' Container (page usually)
Public Shared Sub BindControlsToObject(ByVal obj As Object, ByVal container As Control)
BindControlsToObject(obj, container, String.Empty)
End Sub
'Bind property value to control
Private Shared Function GetControlValue(ByVal control As Control) As Object
If TypeOf control Is TextBox Then
'process text box
Return CType(control, TextBox).Text
ElseIf TypeOf control Is DropDownList Then
'process DropDownList
Return CType(control, DropDownList).SelectedValue
ElseIf TypeOf control Is CheckBox Then
'process CheckBox
Return CType(control, CheckBox).Checked
ElseIf TypeOf control Is HtmlInputHidden Then
'process HtmlInputHidden
Return CType(control, HtmlInputHidden).Value
End If
End Function
#End Region
End Class
Привязка в одну сторону (из объекта в контролы):
Dim testObject As New TestBusinessObject
testObject.Id = Guid.NewGuid().ToString
testObject.Name = "name"
testObject.City = "NY"
testObject.HasSomething = True
BindingHelper.BindObjectToControls(testObject, Page, "obj1_")
Привязка в другую сторону (из контрола в объект):
Dim testObject As New TestBusinessObject
BindingHelper.BindControlsToObject(testObject, Page, "obj1_")
Данная реализация имеет два ограничения:
1) названия контролов (их идентификаторы) должны совпадать с названиями свойств. Либо если мы используем префикс, то должны быть в формате ПРЕФИКСИМЯСВОЙСТВА, например obj1_Id;
2) сейчас обрабатываются только контролы типа TextBox, DropDownList, CheckBox и HtmlInputHidden, но это легко расширяется вами (возможно, вам понадобится поддержка Calendar или чего-то в этом духе).
Удобства: мы избегаем рутинной работы по заполнению соответствий между свойствами объекта и контролами в обе стороны - когда хотим отобразить объект или после PostBack.