Click here to Skip to main content
Click here to Skip to main content

ASP.NET automatic Object to UI Binding

, 25 Apr 2012 CPOL
Rate this:
Please Sign up or sign in to vote.
Easily bind a class to .NET data controls like GridView, FormView, etc., and get an updated object or list back in the code-behind effortlessly.

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:

  1. 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.
  2. 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>&nbsp;
    <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:

' Declare Object Binders as Page level Variables
Dim dsCustomer As New ObjectBinder(Of Customer) ' Will be used to bind Customer
Dim dsAddress As New ObjectBinder(Of Address) ' Will be used to bind Addresses

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
        ' Create a dummy Customer
        Dim c As New Customer With {.FirstName = "Razi", .LastName = "Syed", .Email = "<a href="mailto:emailme@razisyed.com">emailme@razisyed.com", .Status = "Active"}

        ' Create dummy addresses for the customer
        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"})

        ' The Object Binder can be initialized by setting an instance or a list
        ' Not setting an instance will basically create an empty datasource

        dsCustomer.SetInstance(c) ' Set Customer Instance (for FormView)
        dsAddress.SetList(c.Addresses) ' Set Address List (for GridView)

    End If

    ' Bind frmCustomer to Data Source (3 lines of code)
    Dim odsCustomer = dsCustomer.GetDataSource
    phDataSources.Controls.Add(odsCustomer)
    frmCustomer.DataSourceID = odsCustomer.ID

    ' Bind grdAddresses to Data Source 
    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:

' Get Customer Object from UI without any effort
Dim c As Customer = dsCustomer.Instance ' Get an instance (for FormView)
c.Addresses = dsAddress.List ' Get a list (for GridView)

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!

License

This article, along with any associated source code and files, is licensed under The Code Project Open License (CPOL)

Share

About the Author

Razi Syed
Software Developer (Senior)
United States United States
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.

Comments and Discussions

 
QuestionBug? PinmemberMember 106518098-Oct-14 11:42 
AnswerRe: Bug? PinmemberRazi Syed15-Dec-14 11:36 
QuestionSmall fix for "The type specified in the TypeName property of ObjectDataSource ... could not be found" error PinmemberHeather Floyd28-Mar-14 6:09 
QuestionC# Version Now Available [modified] PinmemberHeather Floyd14-Mar-14 11:52 
AnswerRe: C# Version Now Available PinmemberRazi Syed19-Mar-14 5:56 
QuestionC# Version Pinmemberjkreber27-Jul-13 7:21 
AnswerRe: C# Version PinmemberHeather Floyd14-Mar-14 11:55 
QuestionMy vote of 5 [modified] Pinmemberioanab7-Dec-12 14:15 
AnswerRe: My vote of 5 PinmemberRazi Syed17-Jan-13 18:44 
SuggestionRe: My vote of 5 PinmemberHeather Floyd14-Mar-14 11:54 
GeneralMy vote of 5 Pinmemberyanivabo25-Jul-12 8:17 
GeneralMy vote of 5 PinmemberForogar7-May-12 6:09 
GeneralDangerous Pinmemberdave.dolan25-Apr-12 5:05 
GeneralRe: Dangerous PinmemberRazi Syed25-Apr-12 5:51 
GeneralRe: Dangerous Pinmemberdave.dolan25-Apr-12 6:07 
GeneralRe: Dangerous PinmemberRazi Syed25-Apr-12 6:38 
GeneralRe: Dangerous Pinmemberdave.dolan25-Apr-12 8:07 
Questionoffice 2010 Pingroupwinserverkey24-Apr-12 18:24 
Questionoffice 2010 Pingroupwinserverkey24-Apr-12 18:23 
QuestionThanks Chris Maunder! PinmemberRazi Syed19-Apr-12 6:16 

General General    News News    Suggestion Suggestion    Question Question    Bug Bug    Answer Answer    Joke Joke    Rant Rant    Admin Admin   

Use Ctrl+Left/Right to switch messages, Ctrl+Up/Down to switch threads, Ctrl+Shift+Left/Right to switch pages.

| Advertise | Privacy | Terms of Use | Mobile
Web02 | 2.8.141223.1 | Last Updated 25 Apr 2012
Article Copyright 2012 by Razi Syed
Everything else Copyright © CodeProject, 1999-2014
Layout: fixed | fluid