Click here to Skip to main content
65,938 articles
CodeProject is changing. Read more.
Articles
(untagged)

ASP.NET Automatic Object to UI Binding

0.00/5 (No votes)
25 Apr 2012 3  
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.

Image 1

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 values into the UI and displaying 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 it 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 its 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 manually into 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!

History

  • 25th April, 2012: Initial version

License

This article has no explicit license attached to it but may contain usage terms in the article text or the download files themselves. If in doubt please contact the author via the discussion board below.

A list of licenses authors might use can be found here