views:

2805

answers:

7

I have a list box control:


<asp:ListBox runat="server" id="lbox" autoPostBack="true" />

The code behind resembles:


private void Page_Load(object sender, System.EventArgs e)
{
    lbox.SelectedIndexChanged+=new EventHandler(lbox_SelectedIndexChanged);
    if(!Page.IsPostBack)
    {
        LoadData();  
    }
}
private LoadData()
{
    lbox.DataSource = foo();
    lbox.DataBind();
}
protected void lboxScorecard_SelectedIndexChanged(object sender, EventArgs e)
{
    int index = (sender as ListBox).selectedIndex;
}

My problem is that when my page receives a post back (when a user makes a selection in the listbox), the selection always "jumps" to the first item in the listbox, so that the index variable in my callback function is always 0.

Seems like this may be a viewstate problem? How can I fix it so that the selection index remains through the postback?

There is no ajax going on, this is .NET 1.0.

Thanks.

EDIT 1 JohnIdol has gotten me a step closer, If I switch the datasource from my original DataTable to an ArrayList, then everything work properly...what would cause this?

Edit 2 It turns out that my DataTable had multiple values that were the same, so that the indexes were treated as the same as all items with the same value...thanks to those who helped!

A: 

I dont know if it makes a difference or not, but i generally attach my controls to events on the front page rather than in the codebehind. In your example i would have done:

<asp:ListBox runat="server" id="lbox" autoPostBack="true" OnSelectedIndexChanged="lboxScorecard_SelectedIndexChanged"  />

Other than that, i would verify that the ViewState is enabled. ViewState can be turned of at the control, page, & even site level.

Briggie Smalls
A: 

It looks to me like you are creating a new eventhandler on each page load. This might be causing the problem. Why not attach the eventhandler declaratively:

<asp:ListBox runat="server" id="lbox" autoPostBack="true" OnSelectedIndexChanged="lbox_SelectedIndexChanged" />

also, why not reference the control directly, instead of casting?

protected void lbox_SelectedIndexChanged(object sender, EventArgs e)
{
    int index = lbox.selectedIndex;
}
HectorMac
I am casting because with .net 1.0, you would have to have the control as an instance variable in the code behind, in .NET 2.0 + the control is accessible without the instance variable.
mmattax
Adding the event listener did not solve my problem...
mmattax
A: 

Have you thought about loading the data earlier - e.g. in OnInit event on the page/user control. This occurs before the postback data is loaded and thus before an on-change can be processed? I believe that should work - but you might want to turn off viewstate!

Jennifer
+1  A: 

What's the output of the foo() function call?

Populating manually the list box you can set indexes to whatever you want (all 0 for example) - so the same thing can happen setting a given dataSource under certain circumstances (one that specifies indexes I suppose). If all the item indexes are 0 the result is that the SelectedIndexChanged event is not raised (index does not change!) and everything is messed up: on post-back selection will go back to the first item in the list.

This would explain it - I cannot think of anything else - it is working fine for me on .NET 2.0 I am using an ArrayList with strings to populate the listBox.

The only way I can reproduce your issue is setting all indexes to 0.

I'd say add a watch to the ListBox and check the indexes at runtime to make sure they're not all zeroes.

JohnIdol
I am data binding with a data table...this is really starting to blow my mind... I surely thought this was an easy thing to fix...
mmattax
try with an arraylist and see what happens just out of curiosity. Make sure the DataTable has only one column
JohnIdol
I just tried an array list, it works... now I just need to figure out whats wrong with my datatable...though it comes right from a db query... any ideas?
mmattax
I think it has more than one column and the second one is being interpreted as index (didn't try yet). Did you try to add a watch to the list box and have a look at the indexes? if they're all the same that's it
JohnIdol
A: 

Works for me too. Does your foo() return the same values every time?

Just as a side note: if possible, you should really do your databinding in OnInit (every time, not just on GETs). If you do it before the call to base.OnInit(...), the contents of your listbox won't have to be serialized and deserialized to and from viewstate and sent across the wire to the client (yes, you will be hitting the database more, but you'll be hitting a system which is located on your local subnet, or even on the same machine. Moreover, the database will likely cache the result).

If you want to build high-performance websites, you need to take a close look at the way you use ViewState. I highly recommend this article: TRULY Understanding ViewState

Rune
My code doe not actually perform databinding as my example shows, I am really databinding on a button click...
mmattax
Have you resolved the problem? If so, what was the solution?
Rune
Oh, never mind, I see you've already posted the solution :-)
Rune
+1  A: 

Databinding DropDownLists/ListBoxes is painful, because they often bind to the wrong values.

I've given up on using DataBind(), and just resort to using a Foreach loop:

foreach (Item i in DataSet)
{
     listBox.Items.Add(etc);
}
FlySwat
+4  A: 

The real issue here is order of events. When you databind in page_load you overwrite the posted data, thats why the selection is not set in the listbox. You can easily overcome this by moving the binding logic to Page_Init.

dfowler
great advice! i've always thought this was some wierdness to do with having viewstate disabled, but even with viewstate disabled my dropdown list works fine when I move my binding code to Init
Simon_Weaver