Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Setting properties on a user control inside a foreach loop

I have a user control that I use on multiple pages to show information about an object. Whenever I need to use this usercontrol, I call a method called Display (on the usercontrol) and pass in some values.

public void Display(string name, List<Items> items)
{
    // Set a few protected properties so I can display values from the aspx page
}

This works fine, but now I need to use this control inside a foreach loop in an aspx page.

<% foreach (var c in Categories) { %>
      <uc:ItemsControl runat="server"/>
<% } %>

The categories object has the methods and properties that I would otherwise pass into the Display method. So how would I properly set the values?

I tried making the properties on the user control public and just setting them in this way:

<uc:ItemsControl Items="<%# c.Items %>" 
                 OtherProperty="<%# c.GetProperty() %>" 
                 runat="server"/>

This doesn't work, because the properties getting sent in are empty. If I use <%= then it doesn't work and actually throws an error because it doesn't recognize 'c' (unless I take off runat="server" then it will at least compile, it still won't work though.

What is the proper way to do this?

Edit: Also, a repeater control might make this easier for databinding, but I'd prefer to avoid the use of any .NET controls.

like image 590
Brandon Avatar asked Oct 29 '09 17:10

Brandon


2 Answers

In a WebForms page, the way this is usually handled by using DataBinding. Instead of a foreach loop, you can use a Repeater control, set its DataSource property to <%#Categories%>, and then use the data-binding syntax in your latter example above, except instead of c, you'll need to cast Container.DataItem to the proper type in your control. Like this:

<%@ Page Language="C#" %>
<script runat="server">
protected void  Page_Load(object sender, EventArgs e)
{
    CategoriesList.DataBind();
}
class Category
{
    public string CategoryName { get; set; }
    public string GetProperty() { return CategoryName; }
    public string[] Items { get { return new string[] {CategoryName + " 1", CategoryName + " 2"}; } }
}
Category[] Categories = new Category[]
{
    new Category { CategoryName = "Shorts" },
    new Category { CategoryName = "Socks" },
    new Category { CategoryName = "Shirts" },
};
</script>
<html>
<body>
<asp:Repeater runat="server" ID="CategoriesList" DataSource="<%# Categories %>">
  <ItemTemplate>
    <uc:ItemsControl 
       Items="<%# ((Category)(Container.DataItem)).Items %>" 
       OtherProperty="<%# ((Category)(Container.DataItem)).GetProperty() %>" 
       runat="server"/>
  </ItemTemplate>       
</asp:Repeater>
</body>
</html>

The only caveat is you'll need to call the DataBind() method of the Repeater somwhere, typically in the Page_Load method.

Personally, I have always found data-binding to be a pain-- both the casting and the need to call data-bind feel much less natural to me than the foreach method you tried above. That's probably the thing I like best about ASP.NET MVC-- your MVC Views can much more easily use the foreach model of iteration which is much more straightforward, IMHO. That said, if you have to stick with WebForms, databinding-with-casting is the path of least resistance.

BTW, your approaches above didn't work because:

  1. runat=server ASP.NET control properties cannot be filled using <%= %> syntax-- that's only useful for plain-text output, not for filling in object properties.

  2. using data-binding syntax ( <%# %>) can definitely be used to fill in control properties, but you need to wrap the control in a data-binding container (like a Repeater) and call DataBind() in order to get the replacement to happen.

like image 170
Justin Grant Avatar answered Oct 11 '22 14:10

Justin Grant


I know this is old, but I found this thread through google quite instant so I'll just type this.

I've just noticed when helping a colleague that you could do like this with UserControls in foreach. Note that I've only tested it through his example.

<% foreach (var c in Categories) { %>
<%    MyControl ctrl = (MyControl)FindControl("ucItem"); %>
<%    ctrl.PropertyToChange = c.Property; %>

      <uc:MyControl runat="server" ID="ucItem"/>
<% } %>

If this is not applicable for you at least it might be for others.

like image 36
peterthegreat Avatar answered Oct 11 '22 13:10

peterthegreat