Building Web Sites with ASP.NET - Part 2
page 2 of 3
by Brian Mains
Feedback
Average Rating: This article has not yet been rated.
Views (Total / Last 10 Days): 22127/ 20

Using the ListView Control

The module I am going to begin to develop is a news section on the site, where it lists the latest news for that site. The ListView control is a great control to use for this module for one simple reason: it gives you complete control over the user interface layout. Having control over the layout creates great flexibility in how the application works, and makes it really easy to append JavaScript code. With a GridView, while it is nice to have this control encapsulate the underlying UI because ASP.NET AJAX scripts need to know what to work with under the scenes, a ListView is much easier to work with.

Take a look at the structure of a ListView below. This list view renders both the read-only and the edit controls at the same time, but hides the textboxes.

Listing 1: News ListView Definition

<asp:ListView ID="lvwNews" runat="server" ItemPlaceholderID="plcNewsList"
      OnItemDataBound="lvwNews_ItemDataBound" InsertItemPosition="LastItem">
      <LayoutTemplate>
            <div id="NewsList">
                  <asp:PlaceHolder ID="plcNewsList" runat="server" />
            </div>
      </LayoutTemplate>
      <ItemTemplate>
            <asp:Label ID="lblNewsHeadline" runat="server" 
                  Text='<%# Eval("Headline") %>' CssClass="NewsTitle" />
            <asp:TextBox ID="txtNewsHeadline" runat="server" 
                  Text='<%# Eval("Headline") %>' style="display:none" />
            <br />
            
            <asp:Label ID="lblNewsDescription" runat="server" 
                  Text='<%# Eval("Description") %>' />
            <asp:TextBox ID="txtNewsDescription" runat="server" 
                  Text='<%# Eval("Description") %>' TextMode="MultiLine"
                  Rows="5" Columns="30" style="display:none" />
            <br />
            
            Posted at <asp:Label ID="lblNewsPostedDate" runat="server" 
                  Text='<%# Eval("CreatedDate") %>' />
            &nbsp;&nbsp;
            <asp:LinkButton ID="lnkEdit" runat="server"
                  OnClientClick="NewsEdit_Click();returnfalse;">Edit</asp:LinkButton>
      </ItemTemplate>
      <ItemSeparatorTemplate>
            <br />
            <hr />
            <br />
      </ItemSeparatorTemplate>
      <InsertItemTemplate>
            <span class="NewsTitle">Headline:</span>
            <asp:TextBox ID="txtNewsHeadline" runat="server" 
                  Text='<%# Eval("Headline") %>' />
            <br />
            
            <span class="NewsTitle">Description:</span>
            <asp:TextBox ID="txtNewsDescription" runat="server" 
                  Text='<%# Eval("Description") %>' TextMode="MultiLine"
                  Rows="5" Columns="30" />
            <br />
            
            <asp:LinkButton ID="lnkSave" runat="server" Text="Save"
                  OnClientClick="NewsInsert_Click();return false;" />
      </InsertItemTemplate>
</asp:ListView>

This approach means that the initial setup of the table renders on the server, and will be manipulated on the client using JavaScript (newer items and edits sent via web services, while the client updates the UI). Notice how the controls are laid out: the TextBox edit controls have their display set to none, rather than setting Visible="false." Visible set to false means the HTML element is not rendered in the browser, which is the wrong response. Also, notice how buttons do not post back; this is prevented by using the "return false;" statement in the OnClientClick. By default, the __doPostback method is called after the OnClientClick code. The return false statement prevents that code from being called.  I would also recommend setting the UseSubmitBehavior for any Button controls to false, so the button does not render as a submit button (which ignores your code and posts back directly).

There should be careful planning in whatever approach is taken. If the control is bound on the server, it means more content is passed over the wire to the client (possibly in the megabytes).  However, if the client renders the UI, then only the data is passed over the wire, and the markup is generated on the client. But this can be more complicated to setup.

However, whatever changes are made to the client are not persisted in ViewState. If using the ListView approach, the ListView has to be rebound on every page load if something changes; otherwise, it would not know about the client-side code additions because it was not in ViewState.  Using the client only approach, the select web service call is called every postback, unless some caching mechanism can be implemented.

Using the ListView route, the insert template and the edit link will only be visible if the user has permissions. Because the news module is in a user control, the user control exposes properties to turn this on or off, and thus the server controls these capabilities.

To insert a new record, use the following code:

Listing 2: Inserting a Row of Data

function NewsInsert_Click() {
      var body = $get("NewsInsertRow");
      var headline = description = null;
 
      for (var index = 0; index < body.childNodes.length; index++) {
            var control = body.childNodes[index];
 
            if (control.id != undefined && control.id != null 
                  && control.id.length > 0) {
                  if (control.id.endsWith("txtNewsHeadline"))
                        headline = control.value;
                  else if (control.id.endsWith("txtNewsDescription"))
                        description = control.value;
            }
      }
 
      var newsItem = {
            Headline: headline,
            Description: description,
            CreatedDate: new Date()
      };
 
      WebSiteStarterKit.Web.Services.NewsService.CreateNewsItem(newsItem,
            function(results, context, method) { createNewsRow(results); },
            function(results, context, method) { },
            body);
}

There is some work in extracting the row information, a challenge that I have been thinking about is how to make more efficient. The problem comes with server-side templates. A server-side template field is not available via a direct reference. What I mean is that any server control on a page can reference it in JavaScript through the following code:

Listing 3: Referencing a server control on the client

var label = $get("<%= lblLabel.ClientID %>");

At runtime, the client ID of the label is used. Client ID is important because when using a master page, the ID of the label could be: ctl100$ContentPlaceHolder$lblLabel, and thus, it is not good to hard-code this value.

The challenge comes with the ListView. The ListView control uses templates, meaning the reference to the control does not work because that control may be repeated numerous times. To reference the txtNewsHeadline control directly will not work because it resides in a template that may or may not be bound, and referencing this way does not work.

I have thought a little about how to get around this. There are a couple ways, which I will discuss later. One of those ways is the approach I used above. The JavaScript code loops through the insert form, looking for a control with the ID of the headline/description fields and extracting their values. In JavaScript, controls (or their underlying elements) can be accessed via the childNodes collection using the client-side HTML reference. But the childNodes collection also contains literals, and thus referencing an element via childNodes[0] may not contain the right result.

Furthermore, I do not like to change code, so my approach is flexible in the sense that I do not have to rewrite code if I change the layout of the page. For instance, if I insert a new header to make the insert section look better, I would not have to change code when this changes childNode collection indexes.

In the web service call at the end, the web service proxy looks something like this:

<method>(<parameters separated by commas>, <success callback>, <failed callback>,
<context>);

The callback methods defined in this instance are inline (functions do not have to be an explicit declaration, but can be passed inline as an anonymous delegate works in C#), but the name of the method could also be provided. This callback calls a method to create a new row in the user interface, using the createNewsRow method.

Listing 4: Creating a new Row

function createNewsRow(newsItem) {
      var body = $get("NewsList");
      var insertRow = $get("NewsInsertRow");
 
      var headlineLabel = document.createElement("SPAN");
      headlineLabel.innerHTML = newsItem.Headline;
      body.insertBefore(headlineLabel, insertRow);
 
      var headlineBox = document.createElement("INPUT");
      headlineBox.value = newsItem.Headline;
      headlineBox.style.display = "none";
      body.insertBefore(headlineBox, insertRow);
 
      body.insertBefore(document.createElement("BR"), insertRow);
 
      var descriptionLabel = document.createElement("SPAN");
      descriptionLabel.innerHTML = newsItem.Description;
      body.insertBefore(descriptionLabel, insertRow);
 
      var descriptionBox = document.createElement("TEXTAREA");
      descriptionBox.rows = 5;
      descriptionBox.cols = 30;
      descriptionBox.value = newsItem.Description;
      descriptionBox.style.display = "none";
      body.insertBefore(descriptionBox, insertRow);
 
      body.insertBefore(document.createElement("BR"), insertRow);
 
      var createdDateLabel = document.createElement("SPAN");
      createdDateLabel.innerHTML = "Posted at: " + 
            newsItem.CreatedDate.format("MM/dd/yyyy hh:mm:ss"+ "&nbsp;&nbsp;";
      body.insertBefore(createdDateLabel, insertRow);
 
      var saveButton = document.createElement("A");
      saveButton.innerHTML = "Edit";
      saveButton.href = "javascript:NewsEdit_Click();return false;";
      body.insertBefore(saveButton, insertRow);
 
      body.insertBefore(document.createElement("BR"), insertRow);
}

This method does the work of appending a new row to the user interface, working asynchronously to add the new entry to the database and to the user interface. This method uses the Document Object Model (DOM) approach to creating the user interface.  It is a top down approach that creates the ion, and then the user interface elements.

So what happens on the backend? A web service is what gets called out of all of this, and the web service writes the data to an XML file that resides in the web project, shown in Listing 5.

Listing 5: Creating a news item via web service

[
WebService(Namespace = "http://tempuri.org/"),
WebServiceBinding(ConformsTo = WsiProfiles.BasicProfile1_1),
System.ComponentModel.ToolboxItem(false),
ScriptService
]
public class NewsService : WebService
{
      #region " Methods "
 
      [WebMethod]
      public NewsItem CreateNewsItem(object newsItem)
      {
            Dictionary<stringobject> values = newsItem 
                  as Dictionary<stringobject>;
            if (values == null)
                  throw new Exception(
                        "Cannot convert newsItem parameter to a collection");
 
            NewsItem item = new NewsItem
                              {
                                    Headline = (string)values["Headline"],
                                    Description = (string)values["Description"],
                                    CreatedDate = DateTime.Now
                              };
 
            XmlDocument document = new XmlDocument();
            document.Load(Server.MapPath("~/App_Data/News.xml"));
 
            XmlElement element = document.CreateElement("Story");
            document.DocumentElement.AppendChild(element);
            element.AppendChild(document.CreateElement("Headline"));
            element.AppendChild(document.CreateElement("Description"));
            element.AppendChild(document.CreateElement("CreatedDate"));
 
            element["Headline"].InnerText = item.Headline;
            element["Description"].InnerText = item.Description;
            element["CreatedDate"].InnerText = item.CreatedDate.ToString();
            document.Save(Server.MapPath("~/App_Data/News.xml"));
 
            return item;
      }
 
      #endregion
}

What gets passed up to the web service is a dictionary of items (this is because what I passed up was in a name/value pair collection, a typical class setup in JavaScript). This means that the values { Headline : "Some Headline", "Description" : "Some Description" } gets converted to a dictionary with a string key and an object value. This is the typical approach; actually, if you use a JavaScriptConverter object, you will see this approach widely used.

The reason for converting objects to string/object is because all objects have to be serialized when passing them from web service to client, or vice versa. Object references cannot be passed in directly; rather, they are broken down into their primitive or serializable parts. This is the same concept that happens when writing data to a database or serializing an object to XML (an approach some Object Databases use). So the web service simply has to read and write data from XML in order to store the data in this solution, but the solution could easily use a database (I typically have used a database to do this).


View Entire Article

User Comments

Title: פיתוח אתרים   
Name: moshiko bracha
Date: 2011-01-16 12:08:23 PM
Comment:
asp .net is the best way to build today... nice post tnx for the info
Title: Mr.   
Name: dengone
Date: 2009-12-19 8:35:10 PM
Comment:
I think I have got what you write.
Thanks a lot.
Title: Executive Director (Commercial & Industrial Business System Development (Head Office)   
Name: Thomas Woon Wei Leou
Date: 2008-11-25 3:52:12 PM
Comment:
I am presently undertaking my model (BSc (Honours in Computer Science & Management); Module of :- Intelligent Decision Making & Selection in tendon with an Advance Intelligent Making using Selective Decisional Process.

I think there would be a great & wider audience in this present field of study & interest. A simple application would be a Webbot (A Realistic Human Clone; with Full Emotions & Senstivity interecting with the Environment (Real World in Applcation Real Life Time Situation)

If there is some interest, I am very much happy to contribute Ideals for Projects of Future System, Science & Technology an Beyond the Real Matter World, i.e. Visions & Dreams & Our Final Destiny.) Regards.






Community Advice: ASP | SQL | XML | Regular Expressions | Windows


©Copyright 1998-2024 ASPAlliance.com  |  Page Processed at 2024-04-18 5:42:16 PM  AspAlliance Recent Articles RSS Feed
About ASPAlliance | Newsgroups | Advertise | Authors | Email Lists | Feedback | Link To Us | Privacy | Search