Home > Article > Web Front-end > Tips for using UserControl to generate HTML
User Control is certainly familiar to everyone. In the process of using ASP.NET, in addition to aspx pages, the most common one is ascx. ascx is a component with independent logic, which provides powerful reuse features and can greatly improve development efficiency when used rationally. Directly generating HTML content through User Control is actually a relatively common technique (especially in the AJAX era). However, there is relatively little content in this area on the Internet. Many people are still struggling to splice strings, so here I use a An example briefly introduces this technique.
Commenting on an object (article, picture, music, etc.) is one of the most common functions in the application. First, we define a Comment class and the "get" method used in it:
public partial class Comment{ public DateTime CreateTime { get; set; } public string Content { get; set; } } public partial class Comment{ private static List<Comment> s_comments = new List<Comment> { new Comment { CreateTime = DateTime.Parse("2007-1-1"), Content = "今天天气不错" }, new Comment { CreateTime = DateTime.Parse("2007-1-2"), Content = "挺风和日丽的" }, new Comment { CreateTime = DateTime.Parse("2007-1-3"), Content = "我们下午没有课" }, new Comment { CreateTime = DateTime.Parse("2007-1-1"), Content = "这的确挺爽的" } }; public static List<Comment> GetComments(int pageSize, int pageIndex, out int totalCount) { totalCount = s_comments.Count; List<Comment> comments = new List<Comment>(pageSize); for (int i = pageSize * (pageIndex - 1); i < pageSize * pageIndex && i < s_comments.Count; i++) { comments.Add(s_comments[i]); } return comments; } }
In order to display a list of comments, we can use a user control (ItemComments.aspx) to encapsulate it. Naturally, paging is also essential:
<asp:Repeater runat="server" ID="rptComments"> <ItemTemplate> 时间:<%# (Container.DataItem as Comment).CreateTime.ToString() %><br /> 内容:<%# (Container.DataItem as Comment).Content %> </ItemTemplate> <SeparatorTemplate> <hr /> </SeparatorTemplate> <FooterTemplate> <hr /> </FooterTemplate></asp:Repeater> <% if (this.PageIndex > 1) { %> <a href="/ViewItem.aspx?page=<%= this.PageIndex - 1 %>" title="上一页">上一页</a> <% } %><% if (this.PageIndex * this.PageSize < this.TotalCount) { %>
Also:
public partial class ItemComments : System.Web.UI.UserControl{ protected override void OnPreRender(EventArgs e) { base.OnPreRender(e); this.rptComments.DataSource = Comment.GetComments(this.PageSize, this.PageIndex, out this.m_totalCount); this.DataBind(); } public int PageIndex { get; set; } public int PageSize { get; set; } private int m_totalCount; public int TotalCount { get { return this.m_totalCount; } } }
Then use this component in the page (ViewItem.aspx):
<p id="comments"><demo:ItemComments ID="itemComments" runat="server" /></p>
And:
public partial class ViewItem : System.Web.UI.Page{ protected void Page_Load(object sender, EventArgs e) { this.itemComments.PageIndex = this.PageIndex; } protected int PageIndex { get { int result = 0; Int32.TryParse(this.Request.QueryString["page"], out result); return result > 0 ? result : 1; } } }
The effect after opening ViewItem.aspx is as follows:
Time: 2007/1/1 0:00:00 Content: The weather is good today
Time: 2007/1/2 0:00:00 Content: Pretty and sunny
Time: 2007/1/3 0:00:00 Content: We have no classes in the afternoon
Next page
The function of this page is very simple, that is, to view comments. The page number of the current comment will be specified using the page item of QueryString, and then the properties of the ItemComments.ascx control are obtained and set in ViewItem.aspx. The ItemComments control will obtain data and bind it based on its own properties. As for the display content, it is all defined in ascx. Due to the need for paging function, this comment control also contains links to the previous page and the next page. The target of their links is very simple, which is the ViewItem.aspx page, and only the Query String of the page number is added.
The function is completed, but I suddenly feel uncomfortable while using it. Why? Because when we turn the page, or when the user posts a comment, the entire page is refreshed. This is not good. You must know that there may be several other display parts in the ViewItem page, and they are unchanged. And if several other parts also need to be paginated, then it may be necessary to retain the current page number of each part on the page, so the development complexity is still relatively high.
Then we might as well use AJAX. Whether the user turns the page or leaves a comment while viewing the comments, it will not affect other content on the page. To develop this function, server-side support is naturally required, so how to do it? Generally, we always have two options:
The server returns JSON data and operates the DOM on the client for rendering.
The server directly returns the HTML content, and then sets the container on the client (for example, p with the id of comments above).
However, no matter which approach is adopted, the "presentation" logic is usually written again (the first presentation logic is written in ItemComments.ascx). If you use the first approach, then the presentation logic needs to be rendered on the client side by manipulating the DOM; if you use the second approach, then you need to perform string concatenation on the server side. Either approach violates the DRY principle. When the presentation method in ItemComments.ascx is modified, the other place must also be modified accordingly. Moreover, whether it is operating DOM elements or splicing strings, it is more troublesome to maintain, and the development efficiency is naturally not high.
How great would it be if we could get the HTML content directly from the ItemComments control - so let's do that. Please look at the following code (GetComments.ashx):
public class GetComments : IHttpHandler{ public void ProcessRequest(HttpContext context) { context.Response.ContentType = "text/plain"; ViewManager<ItemComments> viewManager = new ViewManager<ItemComments>(); ItemComments control = viewManager.LoadViewControl("~/ItemComments.ascx"); control.PageIndex = Int32.Parse(context.Request.QueryString["page"]); control.PageSize = 3; context.Response.Write(viewManager.RenderView(control)); } public bool IsReusable { ... } }
Very simple code, isn't it? Just create the object, set the properties, and then output it via Response.Write. It's really not a big deal - but the key lies in the ViewManager class. Let's take a look at how it is implemented:
public class ViewManager<T> where T : UserControl{ private Page m_pageHolder; public T LoadViewControl(string path) { this.m_pageHolder = new Page(); return (T)this.m_pageHolder.LoadControl(path); } public string RenderView(T control) { StringWriter output = new StringWriter(); this.m_pageHolder.Controls.Add(control); HttpContext.Current.Server.Execute(this.m_pageHolder, output, false); return output.ToString(); } }
There are only two methods in ViewManager: LoadViewControl and RenderView. The function of the LoadViewControl method is to create a Control instance and return it, and the function of the RenderView method is to generate HTML. The trick of this implementation is to use a newly created Page object as the "container" for generating controls. In the end, we actually run the entire life cycle of the Page object and output the results. Since this empty Page object does not generate any other code, what we get is the code generated by the user control.
But to achieve this AJAX effect, two things need to be done.
The first is to simply modify the page turning link in the ItemComments control so that it calls a JavaScript function when it is clicked. For example, the code for "previous page" will become:
<a href="/ViewItem.aspx?page=<%= this.PageIndex - 1 %>" title="上一页" onclick="return getComments(<%= this.PageIndex - 1 %>);">上一页</a>
The second is to implement the client method getComments. Here I used the prototype framework. The advantage is that I can use quite concise code to achieve the AJAX effect of replacing HTML:
<script type="text/javascript" language="javascript"> function getComments(pageIndex) { new Ajax.Updater( "comments", "/GetComments.ashx?page=" + pageIndex + "&t=" + new Date(), { method: "get" }); return false; // IE only }</script>
Done.
In fact, as mentioned before, using UserControl for HTML code generation is a very common technique. Especially as AJAX applications become more and more popular, reasonable use of the methods mentioned above can easily add AJAX effects to our applications. And in many cases, we can use UserControl to edit the content even if we don't need to display the content on the page. Because writing UserControl is much higher in development efficiency and maintainability than concatenating strings. Since this method actually uses the time-tested model of WebForms, it is also quite efficient in terms of execution efficiency. In addition, as for the example just now, using UserCotrol for HTML generation has other benefits:
The page rendering logic is only implemented once, which improves maintainability.
It will not affect the SEO of the page, because the href of 6dc338e96418ddb2f62886b029f4122c on the client side is still valid.
In fact, WebForms is a very powerful model, so the View of ASP.NET MVC also uses the WebForms engine. Through the above example, we can actually do many other things - such as using UserControl to generate XML data, because UserControl itself does not bring any additional content.
The above is the detailed content of Tips for using UserControl to generate HTML. For more information, please follow other related articles on the PHP Chinese website!