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() %>"开发者_如何学Go
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.
While Justin Grant's answer would likely hav worked just fine, we decided to go with just loading the user control and calling the DisplayResults method.
<% ((UserControlType)LoadControl("~/pathToUserControl.ascx"))
.DisplayResults(ItemName, ItemList)); %>
That is not the complete code, but it is what was needed to solve the issue I addressed in the question. By loading the user control this way, we could set the properties we needed and display the uesr control with the correct information.
精彩评论