2014年7月13日 星期日

[RESOLVED] Loop through repeater inside repeater


Hi


I have a page which presents products in categories. The user is given a text box to enter the quantity of each.


So I have a DataSet of categories and within each a DataSet of products. This site is a little tricky because some are weight based and need special treatment.


This all renders perfectly. I now want to collect up the IDs of the items and their values for the basket.


I thought this would involve...


Loop through the Category Repeater Items


For each one, loop through the Products In That Category repeater items.


For each of those, pull the values from the custom properties - ItemID and Quantity.


Can't do the above, because I can't cast the Control to MyControl to access the properties programatically (that was my plan)


Tried doing the loop as above and pulling the form values inside the custom controls. That doesn't work either.


Code in ASPX


 








<%# Eval("CategoryName")%>






ItemID='<%# Convert.ToInt32(DataBinder.Eval(Container.DataItem, "ItemID"))%>'
ItemPhoto='<%# DataBinder.Eval(Container.DataItem, "Image1")%>'
ItemName='<%# DataBinder.Eval(Container.DataItem, "Name")%>'
ItemDetails='<%# DataBinder.Eval(Container.DataItem, "Details")%>'
ItemQuantity='<%# GetBasketQuantity(Convert.ToInt32(DataBinder.Eval(Container.DataItem, "ItemID")))%>'
ItemPrice='<%# GetPrice(Convert.ToInt32(DataBinder.Eval(Container.DataItem, "ItemID")))%>'
IsLooseItem='<%# Convert.ToBoolean(DataBinder.Eval(Container.DataItem, "IsLooseItem"))%>' />










Code to populate it


        rptCategories.DataSource = new DBItem().ListCategoriesForBuy();
rptCategories.DataBind();

Code that's trying to get the values


foreach (RepeaterItem rptCategory in rptCategories.Items)
{
// Get the child control reference
Repeater rItems = (Repeater)rptCategory.FindControl("rptItemsInCategory");

// Get all the child instances (custom controls)
foreach (RepeaterItem itemWidget in rItems.Items)
{
if (itemWidget.ItemType == ListItemType.Item || itemWidget.ItemType == ListItemType.AlternatingItem)
{
if (itemWidget.ID.Contains("ctlSellItem"))
{
// this is one of the widgets
HiddenField fldItemID = (HiddenField)itemWidget.FindControl("hidItemID");
TextBox fldQuantity = (TextBox)itemWidget.FindControl("txtQuantity");

string id = fldItemID.Value;
string qty = fldQuantity.Text;
decimal quantity = 0;

try
{
quantity = Convert.ToDecimal(qty);
}
catch { }

if (ItemIDs.Length > 0) { ItemIDs = ItemIDs + ","; }
ItemIDs = ItemIDs + id;
ItemQuantities = ItemQuantities + Convert.ToString(quantity);
}
}
}
}

it fails on


if (itemWidget.ID.Contains("ctlSellItem"))


because itemWidget is null.


Yet, the parent contains the correct 8 repeater items.


Why?



What is HGM:SellItem?   If SellItem is a webcontrol then you need to look inside that for your actual controls.


if (itemWidget.ItemType == ListItemType.Item || itemWidget.ItemType == ListItemType.AlternatingItem)
{
SellItem s = (SellItem)itemWidget.FindControls("ctSellItem");
// now use s.FindControl to get your quantity controls etc



Thanks AidyF - I worked that out when I read my own post back. I haven't gone down enough levels, good spot :)


Have reworked as follows - your line of code enables that cast I mentioned which I didn't think was possible... much tidier.


// Get all the child instances (custom controls)
foreach (RepeaterItem itemWidget in rItems.Items)
{
if (itemWidget.ItemType == ListItemType.Item || itemWidget.ItemType == ListItemType.AlternatingItem)
{
if (itemWidget.ID.Contains("ctlSellItem"))
{
// this is one of the widgets
SellItem s = (SellItem)itemWidget.FindControl("ctSellItem");
string id = s.ID.ToString();
string qty = s.Quantity.ToString();
decimal quantity = 0;

try
{
quantity = Convert.ToDecimal(qty);
}
catch { }

if (ItemIDs.Length > 0) { ItemIDs = ItemIDs + ","; }
ItemIDs = ItemIDs + id;
ItemQuantities = ItemQuantities + Convert.ToString(quantity);
}
}
}

Result is the same however.


It fails on the same line because ItemWidget is null.


In watch mode, I can see that the 8 children of the category are loaded. There are 8 instances of RepeaterItem and so 8 SellItems in the collection.


But they are all null.


If it's of interest - there's a button which calls the code above which calls a function called CacheForm() and that's the method in which the above resides. So the repeater and children *have* been loaded - which is why they're in the
collection. They're just, er, all null.


This is going to be something very silly that I have missed over which I shall be embarrassed.


 





Aha


Despite itemWidget being null


If you remove


if (itemWidget.ID.Contains("ctlSellItem"))


then the next line


SellItem
s = (
SellItem)itemWidget.FindControl("ctlSellItem");


executes, even though itemWidget cannot contain anything, least of all any SellItems because it is null.


Very odd. But it works now :)



沒有留言:

張貼留言