Thursday, September 9, 2010

Adding Items to the ASP.Net ListView

Have you ever encountered what you thought would be an easy programming task but then realized you were in the middle of a nightmare? This is exactly what happened to me the past few days when I tried to implement the ListView control into my ASP.Net 3.5 project.  Here's a screenshot of my prototype version:


Essentially what I was trying to build was a fancy looking horizontal listbox.  Having no previous experience with the ListView control in ASP.Net, I just assumed that it pretty much worked like the ListBox control.  How incredibly wrong I was!

Binding the ListView to a DataTable was simple enough.  Then, when I determined that I wanted the ListView to be 1 row tall x 4 columns wide, I fairly quickly implemented a Left and a Right DataPager control.  Everything seemed to be on track.

Where things went totally awry though was when I implemented an external "Add New Item" button.  As any reasonable person would assume, I naturally thought that I could instantiate a new DataRow item, append it onto the DataTable, rebind this to the ListView, and then just select the new last item in the control.  Sounds logical, right?  But lo and behold, setting the ListView's "SelectedIndex" property to the index of this new item had NO effect!  This is where the nightmare began.

I tried everything - and I mean everything - to get it to work.  After a countless number of wasted hours I finally got some help from ASP.net regular, Peter, a super bright developer in the Eastern U.S. and this posting.

Simply put, setting the SelectedIndex property does not work under most circumstances.  I do not understand why but it does not.  So in order to show that a given ListView item is selected you have to add special code to the ItemCreated event handler.  Here's an example:

    protected void listView1_ItemCreated(object sender, ListViewItemEventArgs e)
    {
      if (listView1.SelectedIndex > -1)
        return;

      ListViewDataItem item = (ListViewDataItem)e.Item;
      if (item.DataItemIndex == DataTableRowIndex)
      {
        listView1.SelectedIndex = DataTableRowIndex;
        if (listView1.SelectedItemTemplate != null)
        {
          e.Item.Controls.Clear();
          listView1.SelectedItemTemplate.InstantiateIn(e.Item);
        }

        labelListView.Text = DataTableRowIndex.ToString();
      }
    }

Note: In my case, 'DataTableRowIndex' is an integer property that I set in the 'SelectedIndexChanging' event handler.  Doing so then prepares for what occurs in the 'ItemCreated' event handler.  It's like an indirect, arguably manual way of setting 'SelectedIndex'.

Summary

I've added this posting in the hopes that it will save others the grief I experienced because of Microsoft's very poor implementation of this control. On a positive note, the ListView control is very powerful and highly customizable. Here's an example of my finished implementation:


And here you can download a sample test project.