This is a duplicate as commented below but I think we need to keep it around. I did find the duplicate in my searching for help before posting. The explanation here was easier for me to follow than on the duplicate.
When I run the below code I'm getting the Error "No default member found for type Parcel" right after it runs the ParcelsRepeater.DataSource = Split.Parcels command. The error message appears to be highlighting <%#Container.DataItem("PIN")%> in the aspx code.
It never appears to hit the ItemDataBound event.
Imports System.Linq
Public Class SplitCreateParcels
Inherits System.Web.UI.Page
Public Class SplitParcel
Public Sub New()
Parcels = New List(Of Parcel)
End Sub
Public Property Parcels As List(Of Parcel)
End Class
Public Class Cat
Public Property Category As String
End Class
Public Class Parcel
Public Sub New()
Categories = New List(Of Cat)
End Sub
Public Property PIN As String
Public Property Categories As List(Of Cat)
End Class
Public Property _Split As SplitParcel
Protected Sub Page_Load(ByVal sender As Object, ByVal e As System.EventArgs) Handles Me.Load
Dim Split As New SplitParcel
Dim Parcel1 As New Parcel
Dim Parcel2 As New Parcel
Split.Parcels.Add(Parcel1)
Split.Parcels.Add(Parcel2)
Parcel1.PIN = "Test1"
Parcel1.Categories.Add(New Cat With {.Category = "1"})
Parcel1.Categories.Add(New Cat With {.Category = "2"})
Parcel2.PIN = "Test2"
Parcel2.Categories.Add(New Cat With {.Category = "3"})
Parcel2.Categories.Add(New Cat With {.Category = "4"})
ParcelsRepeater.DataSource = Split.Parcels
ParcelsRepeater.DataBind()
End Sub
Protected Sub ParcelsRepeater_ItemDataBound(sender As Object, e As RepeaterItemEventArgs)
If e.Item.ItemType = ListItemType.Item OrElse e.Item.ItemType = ListItemType.AlternatingItem Then
Dim ParentDataItem As Parcel = DirectCast(e.Item.DataItem, Parcel)
Dim ChildRepeater As Repeater = DirectCast(e.Item.FindControl("IntegerRepeater"), Repeater)
ChildRepeater.DataSource = ParentDataItem.Categories
ChildRepeater.DataBind()
End If
End Sub
End Class
<%@ Page Language="vb" AutoEventWireup="false" CodeBehind="SplitCreateParcels.aspx.vb" Inherits="UADWeb.SplitCreateParcels" %>
<!DOCTYPE html>
<html xmlns="http://www.w3.org/1999/xhtml">
<head runat="server">
<title></title>
</head>
<body>
<form id="form1" runat="server">
<div>
<asp:Repeater ID="ParcelsRepeater" runat="server" OnItemDataBound="ParcelsRepeater_ItemDataBound">
<ItemTemplate>
<%#Container.DataItem("PIN")%>
<asp:Repeater runat="server" ID="IntegerRepeater">
<ItemTemplate>
<%#Container.DataItem("Category")%></br>
</ItemTemplate>
</asp:Repeater>
</ItemTemplate>
</asp:Repeater>
</div>
</form>
</body>
</html>
I believe that your problem is this line:
<%#Container.DataItem("PIN")%>
This occurs before ParcelsRepeater_ItemDataBound
as it is handled as part of the databinding.
As you've already shown in your code, you need to cast your DataItem to it's proper type to access the properties. The following should work:
<%#DirectCast(Container.DataItem, [Namespaced Path To your Type].Parcel).PIN%>
It is necessary to provide the full path to your Parcel type because of differences in how code is handled in the codebehind vs mark-up. For an alternative to that syntax you can view this Q&A.
As a different solution, you can just add a literal to your item template and populate it's text in code-behind:
<asp:Repeater ID="ParcelsRepeater" runat="server"
OnItemDataBound="ParcelsRepeater_ItemDataBound">
<ItemTemplate>
<asp:Literal Text="" ID="Pin" runat="server" />
...
then with ParcelsRepeater_ItemDataBound
Dim ParentDataItem = DirectCast(e.Item.DataItem, Parcel)
Dim PinLiteral = DirectCast(e.Item.FindControl("Pin"), Literal)
PinLiteral.Text = ParentDataItem.PIN
...