I'm am trying to figure out how to access a subnode in serialized xml data using a repeater in my asp.net web form application. I can access all the xml element data on the first layer, but not on the second (Benefits).
My issue is that I cannot access Item.Benefits.BenefitImage
or Item.Benefits.Benefit
within the repeater.
Any pointer would be greatly appreciated.
Here is a snippet of my xml data:
<Category Key="acid" Rank="30">
<Intro> ... </Intro>
<Description> ... </Description>
<Benefits>
<Benefit Key="promote_texture">Promote smoother skin texture</Benefit>
<Benefit Key="promote_tone">Promote even skin tone</Benefit>
<Benefit Key="enhance_radiance">Enhance skin radiance</Benefit>
</Benefits>
</Category>
Here is a snippet of the repeater in the .ASPX page:
<asp:Panel runat="server" CssClass="benefits-wrapper">
<asp:Repeater ID="BenefitsList" runat="server" ItemType="OrdinarySite.Models.ProductCategory" SelectMethod="CategoryList_GetData">
<ItemTemplate>
<div class="benefits">
<div class="benefit">
<asp:Image runat="server" CssClass="benefit-img" ImageUrl="<%# Item.Benefits.BenefitImage %>" />
<asp:Label runat="server" CssClass="benefit-desc" Text="<%# Item.Benefits.Benefit %>"></asp:Label>
</div>
</div>
<div class="benefits-copy">
<asp:Label runat="server" CssClass="heading" Text="<%# Item.Name %>"></asp:Label>
<p><%# Item.Description %></p>
</div>
</ItemTemplate>
</asp:Repeater>
</asp:Panel>
Here is a snippet of the repeater in the .ASPX.CS page:
public partial class Category : BasePage
{
public string categoryKey;
protected void Page_Load(object sender, EventArgs e)
{
var key = (string)RouteData.Values["key"];
categoryKey = key;
if (categoryKey != null) {
this.Title = categoryKey;
} else {
Response.Redirect("~/", true);
}
}
public IEnumerable<ProductCategory> CategoryList_GetData() => CacheObject.Categories.Where(x => x.Key == categoryKey);
}
Here is a snippet of the the class:
namespace Site.Models
{
[Serializable]
public class ProductCategory : IComparable<ProductCategory>
{
[XmlAttribute]
public string Key { get; set; }
[XmlAttribute]
public int Rank { get; set; }
[XmlAttribute]
public string Naming { get; set; }
[XmlIgnore]
public List<Product> Products { get; set; }
public string Name => Resources.ProductCategory.ResourceManager.GetString(Key);
public int CompareTo(ProductCategory other) => this.Rank - other.Rank;
public static string XmlFileName => HostingEnvironment.MapPath("~/App_Data/categories.xml");
public string Intro { get; set; }
public string Description { get; set; }
[XmlArray("Benefits"), XmlArrayItem("Benefit")]
public List<BenefitsList> Benefits { get; set; }
[Serializable]
public class BenefitsList
{
[XmlAttribute]
public string Key { get; set; }
[XmlElement]
public string Benefit { get; set; }
public string BenefitImage => $"~/Images/category/benefits/{Key}.svg";
}
public static List<ProductCategory> LoadXmlData( List<Product> products )
{
var cats = SerializerSupport.DeserializeList<ProductCategory>( XmlFileName );
foreach( var c in cats )
{
c.Products = products
.Where( x => x.Details != null && string.Equals( c.Key, x.Details.CategoryKey, StringComparison.OrdinalIgnoreCase ) )
.OrderBy(x => x.Details.Title).ToList();
c.Products.ForEach( x => x.Category = c );
}
cats.Sort();
return cats;
}
}
You need to use nested repeater to display Benefits
within the repeater as follows. See: Nested repeater.
<asp:Panel runat="server" CssClass="benefits-wrapper">
<asp:Repeater ID="BenefitsList" runat="server" ItemType="OrdinarySite.Models.ProductCategory" SelectMethod="CategoryList_GetData">
<ItemTemplate>
<div class="benefits">
<asp:Repeater runat="server" DataSource='<%# Eval("Item.Benefits") %>'>
<div class="benefit">
<asp:Image runat="server" CssClass="benefit-img" ImageUrl="<%# BenefitImage %>" />
<asp:Label runat="server" CssClass="benefit-desc" Text="<%# Benefit %>"></asp:Label>
</div>
</asp:Repeater>
</div>
<div class="benefits-copy">
<asp:Label runat="server" CssClass="heading" Text="<%# Item.Name %>"></asp:Label>
<p><%# Item.Description %></p>
</div>
</ItemTemplate>
</asp:Repeater>
</asp:Panel>