Advertisement
If you have a new account but are having problems posting or verifying your account, please email us on hello@boards.ie for help. Thanks :)
Hello all! Please ensure that you are posting a new thread or question in the appropriate forum. The Feedback forum is overwhelmed with questions that are having to be moved elsewhere. If you need help to verify your account contact hello@boards.ie
Hi there,
There is an issue with role permissions that is being worked on at the moment.
If you are having trouble with access or permissions on regional forums please post here to get access: https://www.boards.ie/discussion/2058365403/you-do-not-have-permission-for-that#latest

C# question: Accessing a Repeater List in a DropDownList event handler...

  • 13-04-2011 3:38pm
    #1
    Closed Accounts Posts: 3,912 ✭✭✭


    Hi Folks,

    I have a Shopping Cart on my site using the code below in my CodeBehind page. The code below handles the quantity of items for each row in the cart:

    private void CartItemCommand(object source, RepeaterCommandEventArgs e)
    {
    if (Session["Cart"] == null) return;
    var Quantity = (TextBox)e.Item.FindControl(_Quantity");

    switch (e.CommandName)
    {
    case "Remove Item":
    {
    var cartItems = (List<CartItem>)Session["Cart"];


    cartItems.RemoveAt(e.Item.ItemIndex);

    UpdateShoppingSession(cartItems);
    }
    break;


    case "Update Quantity":
    {


    int intQuantity;
    var cartItems = (List<CartItem>)Session["Cart"];
    cartItems[e.Item.ItemIndex].Quantity = intQuantity;
    UpdateShoppingSession(cartItems);
    }
    break;
    }


    As you can see, I use a TextBox called _Quantity to provide for the user to change the value for the quantity for that particular item in the cart.

    What I want to do is remove the Textbox and replace it instead with a DropDownList, (to only allow the user to pick a quanity of between 1 and 10 and eliminate the possibility of malious/unwanted code/quantities being put into the TextBox), populated with int's 1-10 which is bound back to a SQL DataSource which is bound to my MS Server 2005 table with int items 1,2,3,4,5,6,7,8,9,10 held in the table, and I want to replace the "Update Quantity", functionality, (which updates the cart with the new "updated" quantity), and after removing this bit of code, have the "update" functionality handled within my _Quantity_OnSelectedIndexChanged event handler.

    I thought this was just a matter of deleting some of my code above, so I'd just have the code that dealt with removing an item from the cart altogether, and then adding in a separate event handler that dealt with what happens when the DropDownList SelectedIndexChanged condition, which left me with the following code:

    private void CartItemCommand(object source, RepeaterCommandEventArgs e)
    {
    if (Session["Cart"] == null) return;
    var Quantity = (DropDownList)e.Item.FindControl(_Quantity");

    //Note above, changed control type from TextBox to DropDownList

    switch (e.CommandName)
    {
    case "Remove Item":
    {
    var cartItems = (List<CartItem>)Session["Cart"];


    cartItems.RemoveAt(e.Item.ItemIndex);

    UpdateShoppingSession(cartItems);
    }
    break;
    }

    My code section for repacing the "Update Quantity" functionality, I thought I could just replace with:

    protected void _Quantity_OnSelectedIndexChanged(object sender, EventArgs e)
    {
    int intQuantity;
    var cartItems = (List<CartItem>)Session["Cart"];
    cartItems[e.Item.ItemIndex].Quantity = intQuantity;
    //Line above at "Item" is causing Intellisense and compilation error...
    UpdateShoppingSession(cartItems);
    }

    And in my aspx page, I'd just have:

    <asp:DropDownList ID="_Quantity" runat="server" DataSourceID="SqlDataSource1" AutoPostBack="true" OnSelectedIndexChanged="_Quantity_OnSelectedIndexChanged" SelectedValue='<%# ((CartItem)Container.DataItem).Quantity %>'>

    My DropDownList is present and populated with the list of ints 1-10, The correct current value for the Quantity is being displayed, but I can't get the solution above to fire and update on the dropdown list event handler, if the item is changed in the DropDownList as I want it to...

    The problem seems to be the line of code below:

    cartItems[e.Item.ItemIndex].Quantity = intQuantity;

    When this line of code is put within this event handler:

    private void CartItemCommand(object source, RepeaterCommandEventArgs e)
    {

    }

    I get no error, however when I put it within this event handler:


    protected void _Quantity_OnSelectedIndexChanged(object sender, EventArgs e)
    {

    }

    I get an IntelliSense error under where I've enlarged the "Item" word above in the line of code causing the issue and a compilation error saying:

    [FONT=Arial, Helvetica, Geneva, SunSans-Regular, sans-serif]CS0123: No overload for '_Quantity_OnSelectedIndexChanged' matches delegate 'System.EventHandler'[/FONT]

    I think I can work out that I'm trying to access a list that is availble within RepeaterCommandEventArgs but not reachable/accessable within object sender, EventArgs.

    Just wondering is there something I need to add in before the line of code above to access the list I need to access?

    Obviously if I want stuff to get done when the value in my DropDownList is changed, I need to use the _Quantity_OnSelectedIndexChanged event handler to manage what I want done, but the problem seems to be here that within that particular event handler, I can't access the CartItems list that I need to access to get my changes properly updated, or at least I can't access the list in the way I'm incorrectly trying to do it above...

    Any help with this much appreciated, sorry for the over elaboration on this, just wanted to be as descriptive as I could be while not being fully sure of the correct way to describe the problem I'm having as I haven't run into this one before...


Comments

  • Closed Accounts Posts: 3,912 ✭✭✭HellFireClub


    Just updating this if anyone can point me in the right direction:

    I've done away with the event handler for my DropDownList_OnSelectedChanged event and instead tried this:

    <asp:Repeater ID="_ShoppingCart" runat="server" OnItemDataBound="MyRepeaterFunction">

    protected void MyRepeaterFunction(object sender, RepeaterItemEventArgs e)
    {

    DropDownList Quantity = (DropDownList)e.Item.FindControl("_Quantity");
    var cartItems = (List<CartItem>)Session["Cart"];
    cartItems[e.Item.ItemIndex].Amount = int.Parse(Quantity.SelectedValue);
    UpdateShoppingSession(cartItems);
    }

    The problem with this is that I'm getting a compilation error in MS VWD 2010 saying that my index is out of range (value of -1 showing when I hover the cursor over "ItemIndex" above in red???

    Any advice much appreciated...


  • Closed Accounts Posts: 3,912 ✭✭✭HellFireClub


    Anyone?!?!?!?


  • Registered Users, Registered Users 2 Posts: 1,311 ✭✭✭Procasinator


    Have you verified that the FindControl("_Quantity") is actually returning the DropDownList.
    Does your repeater have a HeaderItem?

    Add a check to see that you are looking at a Item or AlternatingItem before (not tested):
    if (e.ItemType == ListItemType.Item || e.ItemType == ListItemType.AlternatingItem) {
        DropDownList Quantity = (DropDownList)e.Item.FindControl("_Quantity");
        var cartItems = (List<CartItem>)Session["Cart"];
        cartItems[e.Item.ItemIndex].Amount = int.Parse(Quantity.SelectedValue);
        UpdateShoppingSession(cartItems);
    }
    

    Otherwise, you might be trying to use e.Item.ItemIndex in HeaderItem and FooterItem, which you are not meant to do.

    You also shouldn't have to use Session for this kind of task, especially if everything is be stored in the ViewState anyhow.


  • Closed Accounts Posts: 3,912 ✭✭✭HellFireClub


    Have you verified that the FindControl("_Quantity") is actually returning the DropDownList.
    Does your repeater have a HeaderItem?

    Add a check to see that you are looking at a Item or AlternatingItem before (not tested):
    if (e.ItemType == ListItemType.Item || e.ItemType == ListItemType.AlternatingItem) {
        DropDownList Quantity = (DropDownList)e.Item.FindControl("_Quantity");
        var cartItems = (List<CartItem>)Session["Cart"];
        cartItems[e.Item.ItemIndex].Amount = int.Parse(Quantity.SelectedValue);
        UpdateShoppingSession(cartItems);
    }
    
    Otherwise, you might be trying to use e.Item.ItemIndex in HeaderItem and FooterItem, which you are not meant to do.

    You also shouldn't have to use Session for this kind of task, especially if everything is be stored in the ViewState anyhow.

    Thanks so much for replying, that's exactly what the problem is, my code isn't finding the DropDownList control...


  • Registered Users, Registered Users 2 Posts: 1,311 ✭✭✭Procasinator


    Thanks so much for replying, that's exactly what the problem is, my code isn't finding the DropDownList control...

    Problem solved so?


  • Advertisement
  • Closed Accounts Posts: 3,912 ✭✭✭HellFireClub


    Problem solved so?

    'Fraid not, I'm getting an error for itemType saying:

    'System.Web.UI.WebControls.RepeaterItemEventArgs' does not contain a definition for 'ItemType' and no extension method 'ItemType' accepting a first argument of type 'System.Web.UI.WebControls.RepeaterItemEventArgs' could be found (are you missing a using directive or an assembly reference)...

    EDIT: I had a HeaderTemplate in the Repeater but have just removed it to see if it helps...


  • Registered Users, Registered Users 2 Posts: 1,311 ✭✭✭Procasinator


    'Fraid not, I'm getting an error for itemType saying:

    'System.Web.UI.WebControls.RepeaterItemEventArgs' does not contain a definition for 'ItemType' and no extension method 'ItemType' accepting a first argument of type 'System.Web.UI.WebControls.RepeaterItemEventArgs' could be found (are you missing a using directive or an assembly reference)...

    EDIT: I had a HeaderTemplate in the Repeater but have just removed it to see if it helps...

    Well, that is my fault, I didn't test my code and I had missed the .Item.

    Should read e.Item.ItemType instead of e.ItemType.

    Sorry about that.


  • Closed Accounts Posts: 3,912 ✭✭✭HellFireClub


    Well, that is my fault, I didn't test my code and I had missed the .Item.

    Should read e.Item.ItemType instead of e.ItemType.

    Sorry about that.

    Gonna try that now, the problem is defo that my DropDownList control isn't being picked up by FindControl, I've tried:

    DropDownList _Quantity = FindControl("_Quantity") as DropDownList;

    DropDownList _Quantity = this._Cart.FindControl("_Quantity") as DropDownList;

    But am getting a Null exception error, object not pointing to an instance of an object or something to that effect, please use the "new" keyword...


  • Registered Users, Registered Users 2 Posts: 1,311 ✭✭✭Procasinator


    Gonna try that now, the problem is defo that my DropDownList control isn't being picked up by FindControl, I've tried:

    DropDownList _Quantity = FindControl("_Quantity") as DropDownList;

    DropDownList _Quantity = this._Cart.FindControl("_Quantity") as DropDownList;

    But am getting a Null exception error, object not pointing to an instance of an object or something to that effect, please use the "new" keyword...

    If it returning null, it means it isn't there (usually).

    This could happen in your Header and Footer, so you will need that check. However, if there is meant to be a drop down per row you should be able to find it.

    Can you post the aspx code too?


  • Closed Accounts Posts: 3,912 ✭✭✭HellFireClub


    If it returning null, it means it isn't there (usually).

    This could happen in your Header and Footer, so you will need that check. However, if there is meant to be a drop down per row you should be able to find it.

    Can you post the aspx code too?
            <asp:Repeater ID="_Cart" runat="server">
        
        <HeaderTemplate>
        <table border="0" width="97%">
        
        <tr>
        <td><div class="p1"><b>Description</b></div></td>
        <td><div class="p1"><b>Item</td>
        <td><div class="p1"><b>Qnty</b></div></td>
        <td><div class="p1"><b>Total</b></div></td>
        <td><div class="p1"><b>Update</b></div></td>
        <td><div class="p1"><b>Remove</b></div></td>
        <td>&nbsp;</td>
        </tr>
       
        
        </HeaderTemplate>
        
        
        
        <ItemTemplate>
        
        <tr>
        <td><div class="p4"><b><%# ((CartItem)Container.DataItem).Name %></b></div>
        <div class="p4"><%# ((CartItem)Container.DataItem).Description %></div></td> 
        <td><div class="p6">&#8364;<%# ((CartItem)Container.DataItem).InvoiceAmountDue.ToString("F2")%></div></td>
        <td><div class="p6"><asp:DropDownList ID="_Amount" runat="server" AutoPostBack="[COLOR=Red]true[/COLOR]" OnSelectedIndexChanged="_Quantity_OnSelectedIndexChanged" Text="<%# ((CartItem)Container.DataItem).Quantity.ToString(CultureInfo.InvariantCulture) %>">
        <asp:ListItem>1</asp:ListItem>
        <asp:ListItem>2</asp:ListItem>
        <asp:ListItem>3</asp:ListItem>
        <asp:ListItem>4</asp:ListItem>
        <asp:ListItem>5</asp:ListItem>
        <asp:ListItem>6</asp:ListItem>
        <asp:ListItem>7</asp:ListItem>
        <asp:ListItem>8</asp:ListItem>
        <asp:ListItem>9</asp:ListItem>
        <asp:ListItem>10</asp:ListItem>
        </asp:DropDownList></div></td>
        <td><div class="p6">&#8364;<%# ((CartItem)Container.DataItem).TotalPrice.ToString("F2")%></div></td>
        <td><asp:LinkButton ID="_Update" CommandName="Update" runat="server" ForeColor="OrangeRed" Text="Update" /></td>
        <td><asp:LinkButton ID="_Remove" CommandName="Remove" runat="server" ForeColor="OrangeRed" Text="Remove" /></td>
        <tr><td></td></tr>
        <tr><td></td></tr>
        </tr>
       
        </ItemTemplate>
        
        
        <FooterTemplate>
    
        
        </table>
        </FooterTemplate>
        </asp:Repeater>
    
    

    I've the page compiling now, and when I set the AutoPostBack = "false", for the _Quantity DropDownList, and I comment out the line of code in red below, I can change the selected item from any value between 1-10 and when I hit the "Update" button, the code works perfectly and my shopping cart gets updated with the new quantity...

    The problem is that I want the update to work off the _QuantityOnSelectedIndexChanged event handler:
            protected void _Quantity_OnSelectedIndexChanged(object sender, EventArgs e)
            {                
    
                var cartItems = (List<CartItem>)Session["Cart"];
                foreach (CartItem Item in cartItems)
    
                {
    
                   [B][COLOR="Red"]
                     DropDownList _Amount = FindControl("_Quantity") as DropDownList;
                     Item.Quantity = int.Parse(_Quantity.SelectedValue);
                     UpdateShoppingSession(cartItems);
    
    [/COLOR][/B]            
    
                }
                
            }
    

    Can't understand how FindControl works fine in the "Update" CommandName button event handler but won't find the DropDownList _Quantity in the _Quantity_OnSelectedIndexChanged

    :confused::confused::confused:


  • Advertisement
  • Registered Users, Registered Users 2 Posts: 527 ✭✭✭Sean^DCT4


    try:
    DropDownList _Amount = _Shopping.FindControl("_Quantity") as DropDownList;
    

    Where _Shopping is the ID of the repeater.

    instead of:
    DropDownList _Amount = FindControl("_Quantity") as DropDownList;
    


  • Closed Accounts Posts: 3,912 ✭✭✭HellFireClub


    Sean^DCT4 wrote: »
    try:
    DropDownList _Amount = _Shopping.FindControl("_Quantity") as DropDownList;
    
    Where _Shopping is the ID of the repeater.

    instead of:
    DropDownList _Amount = FindControl("_Quantity") as DropDownList;
    


    Just tried that, same result, "Object reference not set to an instance of an object."

    Really weird prob, I've used FindControl before loads of times and never run into this kind of an issue...


  • Registered Users, Registered Users 2 Posts: 1,311 ✭✭✭Procasinator


           [...]
        <ItemTemplate>
        [...]
    [B]<asp:DropDownList ID="[COLOR="red"]_Amount[/COLOR]" runat="server" AutoPostBack="true" OnSelectedIndexChanged="_Quantity_OnSelectedIndexChanged" Text="<%# ((CartItem)Container.DataItem).Quantity.ToString(CultureInfo.InvariantCulture) %>">[/B]
    [..]
       
        </ItemTemplate>
        
    [...]
    
    
            protected void _Quantity_OnSelectedIndexChanged(object sender, EventArgs e)
            {                
    
                var cartItems = (List<CartItem>)Session["Cart"];
                foreach (CartItem Item in cartItems)
    
                {
    
                   [B]
                     DropDownList _Amount = [COLOR="Red"]FindControl("_Quantity")[/COLOR] as DropDownList;[/B]
                     Item.Quantity = int.Parse(_Quantity.SelectedValue);
                     UpdateShoppingSession(cartItems);            
                }
                
            }
    

    Can't understand how FindControl works fine in the "Update" CommandName button event handler but won't find the DropDownList _Quantity in the _Quantity_OnSelectedIndexChanged

    :confused::confused::confused:

    In this code listing, the DropDownList has an ID of _Amount rather than _Quantity. (See red bits)

    Saying that, you don't need to find the control as it is passed in your event handler. Just typecast the sender:
    DropDownList Quantity = (DropDownList) sender;
    


  • Closed Accounts Posts: 3,912 ✭✭✭HellFireClub


    In this code listing, the DropDownList has an ID of _Amount rather than _Quantity. (See red bits)

    Saying that, you don't need to find the control as it is passed in your event handler. Just typecast the sender:
    DropDownList Quantity = (DropDownList) sender;
    

    Oop I meant to say that I changed the name from _Quantity to _Amount but I'm sure that the naming matches up on the codebehind page and the aspx page...


  • Closed Accounts Posts: 3,912 ✭✭✭HellFireClub


    In this code listing, the DropDownList has an ID of _Amount rather than _Quantity. (See red bits)

    Saying that, you don't need to find the control as it is passed in your event handler. Just typecast the sender:
    DropDownList Quantity = (DropDownList) sender;
    

    Man you're a genius, that's sorted it out! Thanks so much for your help!


  • Closed Accounts Posts: 3,912 ✭✭✭HellFireClub


    Only problem I have now after testing the code is that if I have more than one Item in my ShoppingCart, say I have 3 items and therefore I have 3 DropdownLists on the page, if I change the quantity say in the first item or the second one or the third one, the other two DropDownLists will update with the same quantity that I've just changed the other one DropDownList to!


  • Closed Accounts Posts: 3,912 ✭✭✭HellFireClub


    I think the issue I have now is that I can't access the controlled list on my List<CartItem>, outside of the repeater event hander...

    I think I need a solution of some kind that lets me put the code below into my: protected void _Amount_OnSelectedIndexChanged(object sender, EventArgs e) event handler:

    //the code snippet below is exactly what was used in my "update" CommandName Button "Update" event handler in my Repeater:


    int intAmount;
    Int32.TryParse(amount.Text, out intAmount);

    var cartItems = (List<CartItem>)Session["Cart"];
    cartItems[e.Item.ItemIndex].Amount = intAmount;
    UpdateShoppingSession(cartItems);

    I've changed the TextBox to a DropDownList, but I think it should still work if I can get to work on the controlled list for my cart using "Item"...

    The "Item" in red above is causing an intellisense compilation and error:

    Error 1 'System.EventArgs' does not contain a definition for 'Item' and no extension method 'Item' accepting a first argument of type 'System.EventArgs' could be found (are you missing a using directive or an assembly reference?)


  • Registered Users, Registered Users 2 Posts: 11,989 ✭✭✭✭Giblet


    That's because you are using "EventArgs e". Have you polled the sender object?

    Have you tried dynamically adding the selected index changed event to the dropdown inside the "onItemCreated" event of the repeater?


  • Closed Accounts Posts: 3,912 ✭✭✭HellFireClub


    Giblet wrote: »
    That's because you are using "EventArgs e". Have you polled the sender object?

    Have you tried dynamically adding the selected index changed event to the dropdown inside the "onItemCreated" event of the repeater?

    This is where I'm completely out of my depth and in new waters! Any help much appreciated with the approach you suggest...


  • Registered Users, Registered Users 2 Posts: 11,989 ✭✭✭✭Giblet


    In your repeater declaration on the aspx / ascx page, add the property
    OnItemCreated="MyFunction"
    protected void MyFunction(RepeaterItemEventArgs e)
    {
       //Do ItemType Checks here
        DropDownList ddlQuantity = e.Item.FindControl("_Quantity") as DropDownList;
        if(ddlQuantity != null)
        {
            ddlQuantity.SelectedIndexChanged += new EventHandler(Quantity_SelectedIndexChanged);
        }
    }
    
    protected void Quantity_SelectedIndexChanged(object sender, EventArgs e)
    {
        DropDownList ddl = sender as DropDownList;
    
    
    }
    

    You can probably setup the SelectedIndexChanged function in the control design as well (Don't have any Visual Studio stuff here to test my work here so forgive me if I've made a mistake). Remember to rebind your control on Page_Load as well.

    Also, consider the move to MVC ;) This nonsense will drive you crazy.


  • Advertisement
  • Moderators, Science, Health & Environment Moderators Posts: 9,035 Mod ✭✭✭✭mewso


    Trying to do this in the selectedindexchanged event is not a good idea as it does not pass any information regarding what row you are dealing with. Why should it care as a dropdownlist doesn't have to be in a databound control. The way you were doing it originally is your best bet since the repeater can tell you what row you are dealing with. A dropdownlist (or the selectedindexchanged event) cannot.

    Personally I would simply have an update cart button and process each row when that is clicked. It skips a lot of the auto-scripting that .net will inject into the page for auto-postback etc. Messy.


  • Closed Accounts Posts: 3,912 ✭✭✭HellFireClub


    mewso wrote: »
    Trying to do this in the selectedindexchanged event is not a good idea as it does not pass any information regarding what row you are dealing with. Why should it care as a dropdownlist doesn't have to be in a databound control. The way you were doing it originally is your best bet since the repeater can tell you what row you are dealing with. A dropdownlist (or the selectedindexchanged event) cannot.

    Personally I would simply have an update cart button and process each row when that is clicked. It skips a lot of the auto-scripting that .net will inject into the page for auto-postback etc. Messy.

    Thanks so much to everyone on thread for helping me out with this, I've decided to revert back to the solution working off the Update button while also allowing me to use the DropdownList in relation to quantities as I need a solution in place rather than no solution and this works great, I was hoping to get rid of the Update button for page space reasons but might come back to it at some point in the future!

    Thanks again to all on thread...


Advertisement