
Introduction
As a developer, I really enjoy working with objects in the code behind. You can call them Classes or POCO or whatever, but it's easy and fun to use them
and write code. However, one of the most repetitive and annoying tasks is to display object properties in UI, and then if a user changes, something,
get it back as an object in your code. The purpose of this utility/framework is to provide two-way binding effortlessly, so that with a few lines of code,
you can bind your object's properties to UI, and then get it back in code behind with updated values without a bunch of manual coding.
Background
Microsoft ASP.NET has really nice controls for performing UI like the GridView or the FormView, that allows Data Binding. They are really great for automatically
plugging in values in to the UI and display them, however, the so-called two way binding is terrible overall, but it's especially bad when it comes to working with objects.
When your user edits something in the UI, and you want to get it back as an object in code-behind, it's a lot of troublesome and repetitive work. You have 2 options:
- You can use an
ObjectDataSource, which will provide 2 way binding, but you will have to write a separate adapter class, and then write the Select, Update, Insert and Delete methods.
- You can handle the binding events in the backend, and use
FindControl to look up each control and then assign each property of the Object to the UI Controls value manually.
Ugh! This is especially cumbersome for grids.
I love the concept of two-way binding, but I find both these techniques annoying. Plus, I hate to place an
ObjectDataSource in the markup and hardcode methods and values
in to it. I still like this first technique where you write a simple Adapter class, and I quickly realized that since the steps are the same for each adapter class,
I can use Generics to create a utility that will automatically provide the adapter, and I don't have to write it separately for each class. I searched for and
reviewed several different frameworks and utilities provided for making two-way databinding happen and easily get the Object back from UI in the code behind,
but I didn't find anything that was very simple, so I ended up writing this very simple
ObjectBinding class.
Using the code
So basically as I stated above, what this utility does is that allows mapping an object to a
GridView of FormView or another ASP.NET control.
As an example, I'll use the following extremely simple classes:
Public Class Customer
Property CustomerID As String
Property FirstName As String
Property LastName As String
Property Status As String
Property Email As String
Property Addresses As New List(Of Address)
End Class
Public Class Address
Property AddressID As String
Property AddressLine As String
Property City As String
Property State As String
Property ZipCode As String
End Class
So Customer is a simple object, and it has a list of Addresses. What we will do is that we'll bind Customer to a
FormView, and it's related addresses
to a GridView, and then demonstrate editing Customer Fields in the UI, or adding/removing/updating an Address in the UI using the Grid, and then get it back
as an object in the code behind with updated values from the UI, with just a few simple lines of code.
So here is the markup. First it's a FormView for the Customer.
<asp:FormView ID="frmCustomer" runat="server" DataKeyNames="CustomerID">
<ItemTemplate>
First Name: <asp:Label ID="lblFirstName" runat="server" Text='<%# Eval("FirstName") %>'></asp:Label><br />
Last Name: <asp:Label ID="lblLastName" runat="server" Text='<%# Eval("LastName") %>'></asp:Label><br />
Email: <asp:Label ID="lblEmail" runat="server" Text='<%# Eval("Email") %>'></asp:Label><br />
Status: <asp:Label ID="lblStatus" runat="server" Text='<%# Eval("Status") %>'></asp:Label><br />
<asp:LinkButton ID="lnkEdit" runat="server" CommandName="Edit">Edit</asp:LinkButton>
</ItemTemplate>
<EditItemTemplate>
<asp:TextBox ID="txtFirstName" runat="server" Text='<%# Bind("FirstName") %>'></asp:TextBox><br />
<asp:TextBox ID="txtLastName" runat="server" Text='<%# Bind("LastName") %>'></asp:TextBox><br />
<asp:TextBox ID="txtEmail" runat="server" Text='<%# Bind("Email") %>'></asp:TextBox><br />
<asp:DropDownList ID="ddlStatus" runat="server" SelectedValue='<%# Bind("Status") %>'>
<asp:ListItem Text="Active" Value="Active"></asp:ListItem>
<asp:ListItem Text="Inactive" Value="Inactive"></asp:ListItem>
</asp:DropDownList>
<br />
<asp:LinkButton ID="btnSave" runat="server" CommandName="Update">Update</asp:LinkButton>
<asp:LinkButton ID="btnCancel" runat="server" CommandName="Cancel">Cancel</asp:LinkButton>
</EditItemTemplate>
</asp:FormView>
As you can see, it's a very simple and basic FormView with some controls that are bound to the Class Properties. We have an
ItemTemplate and also have the EditItemTemplate.
Here is the markup for the GridView for addresses:
<asp:GridView ID="grdAddresses" runat="server"
AutoGenerateColumns="False" DataKeyNames="AddressID">
<Columns>
<asp:BoundField DataField="AddressLine" HeaderText="Address" />
<asp:BoundField DataField="City" HeaderText="City" />
<asp:BoundField DataField="State" HeaderText="State" />
<asp:BoundField DataField="ZipCode" HeaderText="Zip" />
<asp:CommandField ShowEditButton="True" />
<asp:CommandField ShowDeleteButton="True" />
</Columns>
</asp:GridView>
The GridView is even simpler than the FormView.
So now here is the code-behind:
Dim dsCustomer As New ObjectBinder(Of Customer) Dim dsAddress As New ObjectBinder(Of Address)
Here is what we will do in the Page Init event:
Protected Sub Page_Init(ByVal sender As Object, ByVal e As System.EventArgs) Handles Me.Init
If Not Page.IsPostBack Then
Dim c As New Customer With {.FirstName = "Razi", .LastName = "Syed", .Email = "<a href="mailto:emailme@razisyed.com">emailme@razisyed.com", .Status = "Active"}
c.Addresses.Add(New Address With {.AddressLine = "123 Main St.", .City = "Houston", .State = "TX", .ZipCode = "77001"})
c.Addresses.Add(New Address With {.AddressLine = "987 Second St.", .City = "Austin", .State = "TX", .ZipCode = "77002"})
c.Addresses.Add(New Address With {.AddressLine = "456 Third St.", .City = "Dallas", .State = "TX", .ZipCode = "77003"})
dsCustomer.SetInstance(c) dsAddress.SetList(c.Addresses)
End If
Dim odsCustomer = dsCustomer.GetDataSource
phDataSources.Controls.Add(odsCustomer)
frmCustomer.DataSourceID = odsCustomer.ID
Dim odsAddresses = dsAddress.GetDataSource
phDataSources.Controls.Add(odsAddresses)
grdAddresses.DataSourceID = odsAddresses.ID
End Sub
That's pretty much it! The customer and addresses will be displayed to the user. If the user edits/inserts/deletes using the formview or gridview,
it will automatically update the object. The best part is that you can retrieve the object as shown below, without searching for controls and assigning properties manually.
Here is the code to retrieve the object:
Dim c As Customer = dsCustomer.Instance c.Addresses = dsAddress.List
Dim output As String = "Customer: <br>" & _
"First Name: " & c.FirstName & "<br>" & _
"Last Name: " & c.LastName & "<br>" & _
"Email: " & c.Email & "<br>" & _
"Status: " & c.Status & "<br>" & _
"<br>" & _
"Addresses:<br>"
For Each a As Address In c.Addresses
output &= a.AddressLine & ", " & a.City & ", " & a.State & " " & a.ZipCode & "<br>"
Next
lblOutput.Text = output
Points of Interest
The main point of interest is of course the ObjectBinder class. The code is attached in the download. it's actually very simple,
especially considering the huge task it accomplishes!
What this class does is that it creates an ObjectDataSource
and a method for List, Update, Insert and Delete. It uses .Net Generics to allow pretty much any class to work with this simple utility, instead
of having to create a separate adapter class, and plug it in manually in to an
ObjectDataSource in the markup.
This gives you a very nice and easy way to implement MVVM architectural pattern in ASP.NET WebForms.
Cleanup
The ObjectBinder uses the session to store information and if not properly cleared up, it can cause issues in the long run as it would and leave
unnecessary items in the Session.
To clean up and remove the items from the session, the "Clear" method should be called in the Page's unload method.
The alternate is to include the class file in your web app project, and change the code to use the ViewState instead of the session. I am working
on implementing IDisposable for ObjectBinder so it would automatically do the cleanup, but till then a manual call to "Clear" is needed.
Enjoy!
My area of expertise is developing management database systems for business so that they can efficiently store and lookup existing customer's information and related data, and be able to generate various reports. My goal is to always deliver innovative design and a user friendly interface.