我已经尝试了几个小时,现在无法找出为什么我的代码(又名,我)失败了
基本上......我有一个listview控件,我正在传递产品的数据表(ID,名称,描述和价格列),并且我试图这样做,以便当按下“结帐”按钮时,它解析页面上的所有控件,找到具有正确ID的所有控件,并将项值添加到购物车。
我已经检查了源代码中的所有ID,它们与FindControl方法请求的ID匹配。
抛出的错误是:
Object reference not set to an instance of an object.
Description: An unhandled exception occurred during the execution of the current web request. Please review the stack trace for more information about the error and where it originated in the code.
Line 21: For I = 1 To counter
Line 22: Dim cartItem As New Core.Types.CartItem
Line 23: cartItem.Name = CType(productsContainer.FindControl("product" + I.ToString()), HtmlGenericControl).InnerText
Line 24: cartItem.Quantity = Convert.ToInt32(CType(productsContainer.FindControl("quantity" + I.ToString()), HtmlSelect).Value)
Line 25: cartItem.Price = Convert.ToDecimal(CType(productsContainer.FindControl("price" + I.ToString()), HtmlGenericControl).InnerText.Remove(0, 1))
我的.aspx代码:
<div class="productsContainer" id="productsContainer" runat="server">
<asp:ListView runat="server" ID="lsvProducts">
<LayoutTemplate>
<ul class="lsvProducts">
<li class="highlight">
<div class="productName">
Product
</div>
<div class="productQuantity">
Number of Licenses
</div>
<div class="productPrice">
Price
</div>
</li>
<asp:PlaceHolder ID="itemPlaceHolder" runat="server"></asp:PlaceHolder>
</ul>
</LayoutTemplate>
<ItemTemplate>
<li>
<div style="display: none;">
<%=setCurrent()%>
</div>
<input type="hidden" id='productID<%#Eval("ID")%>' />
<div class="productName" id='product<%=currentItem%>'>
<%#Eval("Name")%>
</div>
<div class="productQuantity">
<select id='quantity<%=currentItem%>'>
<option selected="selected"
value="0">0</option>
<option value="1">1</option>
<option value="2">2</option>
<option value="3">3</option>
<option value="4">4</option>
<option value="5">5</option>
<option value="6">6</option>
<option value="7">7</option>
<option value="8">8</option>
<option value="9">9</option>
<option value="10">10</option>
</select>
</div>
<div class="productPrice" id='price<%=currentItem%>'>
<%#"$" + Convert.ToDouble(Eval("Price")).ToString()%>
</div>
</li>
</ItemTemplate>
</asp:ListView>
</div>
<div class="clearer">
</div>
<div class="purchaseButton">
<asp:Button ID="btnAddCart" runat="server" Text="Add to Cart" />
</div>
</div>
我的代码背后:
Dim counter As Int32
Public currentItem As Int32
Protected Sub Page_Load(ByVal sender As Object, ByVal e As System.EventArgs) Handles Me.Load
'get all active products to display in the listing
Dim query As String = "SELECT * FROM Products WHERE Active = 1"
Dim dt As DataTable = DAL.Data.GetDataTable(query, "MainDB")
counter = dt.Rows.Count
lsvProducts.DataSource = dt
lsvProducts.DataBind()
End Sub
Protected Sub btnAddCart_Click(ByVal sender As Object, ByVal e As EventArgs) Handles btnAddCart.Click
'create a new instance of the cart
Dim cart As New Core.Types.Cart
'foreach item in the listing, find its details and add it to the shopping cart
For I = 1 To counter
Dim cartItem As New Core.Types.CartItem
cartItem.Name = CType(productsContainer.FindControl("product" + I.ToString()), HtmlGenericControl).InnerText
cartItem.Quantity = Convert.ToInt32(CType(productsContainer.FindControl("quantity" + I.ToString()), HtmlSelect).Value)
cartItem.Price = Convert.ToDecimal(CType(productsContainer.FindControl("price" + I.ToString()), HtmlGenericControl).InnerText.Remove(0, 1))
cartItem.ID = Convert.ToInt32(CType(productsContainer.FindControl("productID" + I.ToString()), HtmlGenericControl).InnerText)
cart.AddItem(cartItem)
Next
If (cart.isEmpty) Then
'empty cart, go nowhere. show a message saying the carts empty and to choose something.
Else
Response.Redirect("~/Checkout.aspx")
End If
End Sub
Public Function setCurrent()
currentItem = currentItem + 1
Return currentItem
End Function
请帮助......这让我疯了!
提前致谢:)
答案 0 :(得分:5)
如果您在datagrid / repeater / listview中,要使用“FindControl”方法,您必须遍历列表视图中的数据项,然后对每个项执行查找控制方法。例如在C#中:
foreach(RepeaterItem item in Repeater1.Items)
{
Literal lit = (Literal)item.FindControl("controlId");
}
我不确定这是确切的语法,但你明白我的意思。你不能只使用listview Id上的find控制方法 - 每个项目中的服务器控件的ID都会被重写,因为你正在循环一个集合......
干杯,肖恩
答案 1 :(得分:5)
FindControl只查找当前的命名容器。如果您希望从不同的命名容器中找到控件,您应该拥有自己的(递归)实现。例如:
private Control FindControlRecursive(Control parent, string id)
{
Control controlFound = parent.FindControl(id);
int i = 0;
while (controlFound == null && i < parent.Controls.Count)
{
controlFound = FindControlRecursive(parent.Controls[i++], id);
}
return controlFound;
}
之后使用FindControlRecursive(productsContainer,“product”+ I.ToString())
答案 2 :(得分:1)
看起来你的嵌套控件只是基本的Html控件?我不确定它们是否会在ASP.NET中注册,除非你有runat =“server”将它们注册为服务器端控件。
我已经有一段时间了,因为我已经完成了大量的ASP.NET开发,但在我之前的经验中,我们总是使用服务器端控件并且没有问题。
答案 3 :(得分:0)
我注意到的另一件事是,如果子页面的ContentPlaceHolder嵌套在母版页上的LoginView内的LoggedInTemplate中,那么您可以忘记使用FindControl来获取子页面内控件的句柄。