views:

353

answers:

3

Hey everyone,

Within a repeater control, is there a way of de-binding certain items before the page is rendered?

Currently we have a collection of items being bound to a repeater and if the item is not part of the current language, we hide the item.

I'm wanting to be able to do a count on the repeater and get a valid number back. A count that doesn't also include the hidden items.

Is it possible to de-bind specific items perhaps in the ItemDataBound event?

Update

For each item in the collection we're binding, we check the database during the ItemDataBound for further information about the item, such as language etc. This is currently stopping us from filtering the bound data before binding it.

+2  A: 

A more appropriate solution could be to filter the bound collection if there is no specific need in those hidden items. Something like

items.Where(i => i.IsInLanguage(currentLanguage));

Update:

As for me I'd use this approach:

var items = db.
      Where(i => i.IsInLanguage(currentLanguage)).
      Where(i => i.SomeField == anotherFilterParameter);

repeater.DataSource = items;
repeater.DataBind();

So all filtering is applied beforehand

This will reduce the number of round-trips to the database as well, which plays for better performance

dh
I'll update my OQ but basically, we don't know which items to set as visible etc until the ItemDataBound event. Each item has an ID and we go to the DB for extra details at that point.
Jamie Dixon
What happens on ItemDataBound which makes the filtering possible? Is your current language becoming available only at that moment?
dh
yeah. Basically we have something called a collection of "page" ID's and as each item is bound, we go to the database, find out if it's part of the current language and if not, hide the item.
Jamie Dixon
is it possible to get ids of items before binding and query the database which of those ids are suitable this time?
dh
That's also not good for performance reasons to query the database each time an item is databound
dh
+1  A: 

Why not filter the datasource before binding. So assuming you are using some custom objects:

myRepeater.DataSource=repository.getItems().Where(item=>item.Language==CurrentLanguage);

If you don't need them don't bind them in the first place.

Update

If it's at all possible you should probally pull that info from the DB upfront. Are these lists large? If so hitting the db once for each item in the list will show up as a performance problem.

JoshBerke
+2  A: 

I agree with the others answers - the best solution (for both performance and code clarity) is to redesign the page so that you can filter invalid entries out before databinding.

Most data sources don't allow us to remove their items while ASP.NET is iterating them. For example, if you bind to a simple generic List<T>, and you remove an item while iterating it, the list will throw an InvalidOperationException.

In other cases, ASP.NET actually iterates a a copy of the data source. If you bind to a DataTable, ASP.NET uses a copy of the contents (the default DataView) rather than iterating the source rows themselves - you can remove items from the underlying data source while iterating, but it doesn't affect the databinding operation.

If filtering the items in advance really isn't an option, your current solution is fine: just hide the items! If you need to get the correct count on top of that, track the number of invalid items in your ItemDataBound handler and expose it as a page-level property:

if (IsInvalid(args.Item.DataItem)) {
    this.invalidItemCount++;
    // code to hide the current item
}
Jeff Sternal
I'd love to redesign the way the pages work but we're using EPiServer as the CMS and as far as I've found, the current way is the best I've been able to find. I'm currently following your last sugestion to expose a Count property and incriment it for valid items. Might have to stick with that. Thanks for the reply :)
Jamie Dixon