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.
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:
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.
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.
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.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With