• 0

[ASP.Net] Repeaters with Dynamic ItemTemplates


Question

Hey guys, I have abit of a pickle. I want to have in an ItemTemplate a couple of Templates and only want to show one based on the data for that row. Basically I have a normal product list, and then people want to be able to put headings in randomly into that list, so I have a seperate bit of html for that. I thought I might be able to set the table row's to runat="server" and simply hide the ones that I don't need, but I have a code block inside of that row which apparently .Net does not approve of when its parent is set to runat="server" :s. I'm not sure if this would work anyway since the columns are going to be different for a Product row and a heading row, so ASP is still going to try and put info into the bit that I'm going to set to visible="false", which will obviously die with errors?

So I spose the question is, is there a way to use if statements with DataBinded ..data?

Just incase the above doesn't make much sense, here is roughly what I want to do, :p

<ItemTemplate>
   <% if(Data["IsNormalRow"] == true) { %>
   <tr>
	   <td>My Product List</td>
	</tr>
   <% } else if(Data["IsHeadingRow"] == true) { %>
	<tr>
	   <td><h1>My Heading</h1></td>
	</tr>
	<% } else if (Data["IsSomeOtherType"] == true) { %>
	<tr>
	   <td>Another type here</td>
	</tr>
   <% } %>
</ItemTemplate>

Is there a way? :pinch:

11 answers to this question

Recommended Posts

  • 0

Well, instead of trying to force logic into the markup page, what you could do is subclass the standard repeater control, to provide your own item header implementation:

namespace MyCustomControls
{
	public class MyExtendedRepeater : Repeater
	{
		private ITemplate itemHeaderTemplate;

		[TemplateContainer(typeof(ItemHeaderContainer)), PersistenceMode(PersistenceMode.InnerProperty)]
		public ITemplate ItemHeaderTemplate
		{
			get { return itemHeaderTemplate; }
			set { itemHeaderTemplate = value; }
		}

		protected override void OnItemCreated(RepeaterItemEventArgs e)
		{
			base.OnItemCreated(e);

			if (!e.Item.DataItem == null && (e.Item.ItemType == ListItemType.Item || e.Item.ItemType == ListItemType.AlternatingItem))
			{
				if (<insert your header logic here>)
				{
					ItemHeaderContainer container = new ItemHeaderContainer();
					ItemHeaderTemplate.InstantiateIn(container);

					container.DataItem = e.Item.DataItem;
					container.DataBind();
				}
			}
		}
	}

	public class ItemHeaderContainer : Control, INamingContainer
	{
		private object dataItem;
		public virtual object DataItem
		{
			get { return dataItem; }
			set { dataItem = value; }
		}
	}
}

What the above does, is extends the standard .NET implementation of the Repeater, but supplements it with an additional property called ItemHeaderTemplate, which you can use to express your individual headers. What you would need to do is specifically state the logic to decide whether or not the header is needed. I didn't spend to long on this, but of course from here you can expand it to make any generic Grouping Repeater.

Use it in code as follows:

<%@ Register Assembly="App_Code" Namespace="MyCustomControls" TagPrefix="custom" %>

^ That is on the assumption that you've got this class in your App_Code.

<custom:MyExtendedRepeater ID="repeat_Data" runat="server">
	 <ItemHeaderTemplate>item header here</ItemHeaderTemplate>
	 <ItemTemplate>data here</ItemTemplate>
</custom:MyExtendedRepeater>

Is that any help?

  • 0

Hey Antaris. Cheers for the answer. I have the following,

protected override void OnItemCreated(RepeaterItemEventArgs e)
		{
			base.OnItemCreated(e);

			if (e.Item.DataItem != null && (e.Item.ItemType == ListItemType.Item || e.Item.ItemType == ListItemType.AlternatingItem))
			{
				DataRowView dt = (DataRowView)e.Item.DataItem;
				if (dt.DataView.Table.Columns["IsHeading"] != null)
				{
					if ((dt["IsHeading"].ToString()) == "true")
					{
						ItemHeaderContainer container = new ItemHeaderContainer();
						ItemHeaderTemplate.InstantiateIn(container);

						container.DataItem = e.Item.DataItem;
						container.DataBind();
					}
				}
			}
		}

Am I supposed to do something after container.DataBind()? I was stepping through the code, and after that line, it starts trying to put the data into an ItemTemplate.. not an ItemTemplateHeader. :s

  • 0

Bah, sif not let me edit. Sorry, it does go into the ItemHeaderTemplate, but then keeps on moving down into ItemTemplate, and perhaps the ItemTemplate overwrites the ItemHeaderTemplate so it never appears.

Edit Edit: Ok, first problem sovled.

base.Controls.Add(container);

Adds my ItemHeaderTemplate.. now the problem is that it still tries to add an empty item... it seems to do it after the OnItemCreated.. so I can't simply delete the empty item. :(

Edited by Pc_Madness
  • 0

The implementation I tested:

namespace Test
{
	public class MyRepeater : Repeater
	{
		[TemplateContainer(typeof(ItemHeaderContainer)), PersistenceMode(PersistenceMode.InnerProperty)]
		public ITemplate ItemHeaderTemplate { get; set; }

		protected override void OnItemCreated(RepeaterItemEventArgs e)
		{
			base.OnItemCreated(e);

			if (e.Item.ItemType == ListItemType.Item || e.Item.ItemType == ListItemType.AlternatingItem)
			{
				TestItem testItem = e.Item.DataItem as TestItem;
				if (testItem.Header)
				{
					ItemHeaderContainer container = new ItemHeaderContainer();
					ItemHeaderTemplate.InstantiateIn(container);

					container.DataItem = testItem;
					container.DataBind();
					this.Controls.Add(container);
				}
			}
		}
	}

	public class TestItem
	{
		public string Name { get; set; }
		public bool Header { get; set; }
	}

	public class ItemHeaderContainer : Control, INamingContainer
	{
		public object DataItem { get; set; }
	}
}

Doesn't create empty entries, it just works :s

<%@ Page Language="C#" AutoEventWireup="true"  CodeFile="Default.aspx.cs" Inherits="_Default" %>
<%@ Register TagPrefix="local" Assembly="App_Code" Namespace="Test" %>
<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">t;html xmlns="http://www.w3.org/1999/xhtml">;head runat="server">
	<title>Untitled Page</title>
</head>
<body>
	<form id="form1" runat="server">
	<div>
		<local:MyRepeater ID="repeat_Test" runat="server">
			<ItemTemplate>Here is a test item</ItemTemplate>
			<ItemHeaderTemplate><h3>Here is a header</h3></ItemHeaderTemplate>
		</local:MyRepeater>
	</div>
	</form>
</body>
</html>

  • 0
  Antaris said:
The implementation I tested:

How are your rows done in your DataTable? I have rows filled with Product information, and then randomy there are blank rows which has IsHeading and Title filled in and nothing else. Are you sure you aren't combing the two rows into together? (Perhaps I didn't explain it properly :()

I don't understand how your way could work though, at the end of OnItemCreated e (an ItemTemplate) gets added to the Repeater automatically, as I understand it? But we chuck in our own Item before hand, so both are using the same DataRow, and since the DataItem is basically empty, the ItemTemplate code errors.

There doesn't seem to be a way to remove 'e'... is there a way to control what Item gets passed to OnItemCreated instead? Time to venture into the scary world of MSDN :(

  • 0
  Pc_Madness said:
How are your rows done in your DataTable? I have rows filled with Product information, and then randomy there are blank rows which has IsHeading and Title filled in and nothing else. Are you sure you aren't combing the two rows into together? (Perhaps I didn't explain it properly :()

Well, that could be your problem. The binding process will bind every row as an Item (or AlternatingItem). So if you randomly have rows that have no data, just header information, then it will create your ItemHeader, and then create your Item (its not smart enough to realise you don't want to do that.). You may have to have a standard row with an additional column for heading, instead of seperating them out.

The class I have, 'TestItem' defines a property called Header. This would be the equivalent to a header column in your datatable, for all rows.

  • 0
  Antaris said:
Well, that could be your problem. The binding process will bind every row as an Item (or AlternatingItem). So if you randomly have rows that have no data, just header information, then it will create your ItemHeader, and then create your Item (its not smart enough to realise you don't want to do that.). You may have to have a standard row with an additional column for heading, instead of seperating them out.

Yeah, I was hoping to avoid that since the headings don't relate to a single row obviously. The other option I spose is to move the few bits of code I have in ItemTemplate into the Code behind and chuck in some error handling to ignore it if its a heading row, and then set that rows visibility to false. :)

Thanks for your help. :)

  • 0

*bump* Only just spotted this now. I have a Repeater which is supposed to be displaying 141 rows of Products, and then it also has 3 heading rows. So on page load I have 144 items, but on Post back I only have 141, so it trims 3 off the end of the array (which is quite bad obviously :p). If I don't do a redirect after the postback, my heading rows are appearing as normal rows again. Do I have to do something so that they survive a postback? :(

  • 0
  Pc_Madness said:
Nope. :s

Meh, no matter, I just went back to using a normal repeater and passing the data to the code behind and toggle a row on and off. Its kinda pointless to use a custom repeater if I can't control what kind of item the Repeater will be making.

This topic is now closed to further replies.
  • Recently Browsing   0 members

    • No registered users viewing this page.
  • Posts

    • I just teams to stop stealing the damn focus every time it starts or restarts after an update. Annoying as all hell.
    • Obviously new hardware costs more money. Never said you get new 2025 hardware for $266. You get new 2025 hardware for as little as $399 and only gets better with back to school sales. At the $499-699, there's some decent spec laptops with 16 GB RAM, and 1 TB SSD with better build quality than this lowest end ideapad.
    • FxSound 1.1.34 Beta by Razvan Serea FxSound (formerly DFX Audio Enhancer / FxSound Enhancer) is now free, making high-quality audio enhancement accessible to everyone. Designed for all PC sound systems, from average setups to audiophile-grade equipment, it offers automatic or fully customizable processing. As automatic or customizable as you want, it utilizes the highest-grade processing to deliver more volume, better equalization, and a wider, deeper sound. For the serious audiophiles, FxSound gives you the tools to adjust the FxSound Effects and EQ to your exact preferences. Turn FxSound on and immediately hear the difference in sound quality. FxSound is ideal for budget audiophiles, music lovers, gamers, transcriptionists, Netflix enthusiasts, and more. It’s particularly beneficial for those relying on quiet laptop speakers or low-quality audio hardware. As a free tool, FxSound excels in boosting volume, enhancing bass, and improving sound quality. No other free EQ for Windows matches its ease of use. FxSound Is Now Completely Free and Unrestricted FxSound Pro is now free for everyone, not just those who can afford it. Get free and unrestricted access to better sound today. FxSound is now entirely supported by users. Click here to donate to help fund continued development and improvements to FxSound. FxSound 1.1.34 Beta changelog: System tray context menu width is fixed and device names are adjusted to width Prompt to save the preset in a new name if changes are made and new preset is selected If preferred device is not connected then it is disabled and greyed out from selection until connected again Application crash dump is saved on unhandled exceptions Download: FxSound 1.1.34 Beta | ARM64 | ~70.0 MB (Open Source) View: FxSound Home Page | Screenshot Get alerted to all of our Software updates on Twitter at @NeowinSoftware
    • Can you get a brand new (not refurb) device like this, but with 2025 hardware, for $266? Under $300? No? If you can, it must have the worst specs otherwise (4gb ram, 1366x768 12in lcd screen, 256gb spinning hard drive, etc.). Please show me this sub-$300 2025 laptop that is better than what the article shows.
  • Recent Achievements

    • One Year In
      TsunadeMama earned a badge
      One Year In
    • Week One Done
      shaheen earned a badge
      Week One Done
    • Dedicated
      Cole Multipass earned a badge
      Dedicated
    • Week One Done
      Alexander 001 earned a badge
      Week One Done
    • Week One Done
      icecreamconesleeves earned a badge
      Week One Done
  • Popular Contributors

    1. 1
      +primortal
      569
    2. 2
      +FloatingFatMan
      187
    3. 3
      ATLien_0
      187
    4. 4
      Skyfrog
      113
    5. 5
      Som
      109
  • Tell a friend

    Love Neowin? Tell a friend!