Home > .net 3.5, AJAX, c#, LINQ, Visual Studio 2008 > WebGallery 2.0 #3 – Building the Galleries

WebGallery 2.0 #3 – Building the Galleries

February 25, 2008

In our last two posts, we’ve discussed the underlying data model and how LINQ and the HttpHandler wraps everything up to display our photos. 

#1 – Introduction
#2 – HttpHandler and LINQ Data Model

NOTE: Code downloads are available on the Introduction post.

This post will cover how the galleries use those data components and controls such as the Data Pager and ListView to build fully XHTML compliant code.

Gallery File StructureThe galleries consist of two files: Default and Show.  The Default page contains a secondary list of the galleries and a “what’s new” list; Show is responsible for rendering and paging through the list of the galleries.  I could have bypassed Default, but I wanted to leave it in as a backwards compatibility for those unable to access the dropdown menu control (text readers, etc).

Galleries’ Default Page

The ListView control is a new control in ASP.NET 3.5 that renders clean, crisp HTML using server-side templates and placeholders.  The default page contains a extremely simple ListView, so we can start there.

<asp:ListView ID=”GalleriesList” runat=”server”

ItemPlaceholderID=”itemPlaceholder”>

<LayoutTemplate>

<ul class=”galleryList”>

<asp:PlaceHolder ID=”itemPlaceholder” runat=”server” />

</ul>

</LayoutTemplate>

<ItemTemplate>

<li>

<a href=’Show.aspx?id=<%# Eval(“Name”) %>‘>

<%# Eval(“Name”) %>

</a>

</li>

</ItemTemplate>

</asp:ListView>

In the code-behind, simply bind our LINQ data source to the ListView:

GalleriesList.DataSource = db.GetGalleriesByRole(Page.User);

GalleriesList.DataBind();

The List View contains numerous “views”—the example above contains the LayoutTemplate (which describes the layout for the entire control) and the ItemTemplate (which describes the layout for each data item in the DataSource provided to the ListView).  As you can see, the ListView is simply generating an HTML unordered list with each data object creating a list item.

Gallery List ala ListView

Now, this ListView generates clean HTML exactly as we specified:

<ul class=”galleryList”>

<li><a href=’Show.aspx?id=Default’>Default</a></li>

… {trimmed for brevity}

</ul>

That’s great, but what has the ListView saved us? We could have simply used a bit of code and saved using the control:

<ul class=”galleryList”>

<% foreach (var item in db.GetGalleriesByRole(User)) { %>

<li>

<a href=’Show.aspx?id=<%=item.Name %>‘>

<%=item.Name %>

</a>

</li>

<% }%>

</ul>

What it saves us, is time on exception handling and what’s the most common “exception” while coding data sets and lists?  No data!

The ListView control has special containers to return when you your data set is null or empty: the EmptyItemTemplate and EmptyDataTemplate. 

The EmptyItemTemplate is used when your data set has under the number of items you are displaying (e.g. your page has room for 12, but you only have 10). 

The EmptyDataTemplate is provides alternative information to the user when the data set does not contain any results.

<EmptyDataTemplate>

<p>No galleries could be found.</p>

</EmptyDataTemplate>

Galleries’ Show Page

The Show page handles displaying the contents of each gallery.  The Show page (for the end user) consists of two controls: a ListView and a DataPager.

Similar to the Default galleries page, the ListView control generates clean, consistant HTML on our Show page; however, this ListView is a bit more complicated to enable grouping.

Attributes of our ListView:

<asp:ListView ID=”lv” runat=”server” GroupItemCount=”4″

OnPagePropertiesChanged=”lv_PagePropertiesChanged”

       OnItemCommand=”lv_ItemCommand”

OnItemCreated=”lv_ItemCreated”

ItemPlaceholderID=”iPh”

GroupPlaceholderID=”gPh”>

  • GroupItemCount=”4” – Tells the ListView to create a new grouping based on the GroupTemplate every four data items.
  • ItemPlaceHolderId=”iPh” – Since we’re going to be repeating numerous times, rather than using the default itemPlaceholder, shortening it can save us some bytes across the wire.
  • GroupPlaceHolderId=”gPh” – Same as ItemPlaceHolderId.
  • OnItemCreated, OnPagePropertiesChanged, OnItemCommand – We’ll discuss these later.

Inside our ListView’s LayoutTemplate, the first item of business is the Data Pager.  It’s a matter of preference that the data pager appears at the top.  I prefer the control on top because it’s easier to page without waiting for the full page to generate (keeping the mouse in a single location) whereas at the bottom, the pager could “move” based on the height of the gallery items.

<div class=”pager”>

<asp:DataPager ID=”pagerTop” runat=”server” PageSize=”12″>

<Fields>

 

<asp:NextPreviousPagerField ButtonCssClass=”pagerItem”

FirstPageText=”«” PreviousPageText=”‹”

RenderDisabledButtonsAsLabels=”true”

ShowFirstPageButton=”true” ShowPreviousPageButton=”true”

ShowLastPageButton=”false” ShowNextPageButton=”false” />

 

<asp:NumericPagerField ButtonCount=”5″

NumericButtonCssClass=”pagerItem”

NextPreviousButtonCssClass=”pagerItem”

CurrentPageLabelCssClass=”currentPagerItem” />

 

<asp:NextPreviousPagerField ButtonCssClass=”pagerItem”

LastPageText=”»” NextPageText=”›”

RenderDisabledButtonsAsLabels=”true”

ShowFirstPageButton=”false” ShowPreviousPageButton=”false”

ShowLastPageButton=”true” ShowNextPageButton=”true” />

 

</Fields>

</asp:DataPager>

</div>

This creates, once the styles are applied:

Data Pager Control

Important attributes of the DataPager control:

  • PageSize=”12” on the DataPager control tells our data source (the ListView) to return 12 items per page.
  • ButtonCount=”5” on the NumericPagerField tells the pager to create 5 “pages” at a time in the list (see the photo example).
  • RenderDisabledButtonsAsLabels=”true” is extremely important for XHTML compliance.  See my post explaining the topic here.

Note: The gradient idea comes from Matt Berseth, the master of making .net controls look pretty—looks brilliant, thanks!

The rest of our LayoutTemplate consists one a table.  A plain, simple table.

<table id=”gPhC” runat=”server”

class=”galleryList” style=”width: 100%”>

<tr id=”gPh” runat=”server”></tr>

</table>

The table contains our gPh (group placeholder) inside of a gPhC (group placeholder container).  This tells us that our results will be placed inside a table and that each group will be in a new table row.

Now we’re ready to specify the GroupTemplate:

<GroupTemplate>

<tr id=”iPhC” runat=”server”>

              <td id=”iPh” runat=”server”></td>

</tr>

</GroupTemplate>

Inside each HTML table row will be a table cell (four in total) controlled by the ListView.  We’ve defined how the table itself will look, how each group of four will look, now to define exactly what each item will look like using the ItemTemplate.

<ItemTemplate>

<td id=”Td4″ runat=”server” class=”galleryItem”

style=”vertical-align: top;“>

<p>

<strong><%# Eval(“Name”) %></strong>

<br />

<a

href=”../WebStorageHandler.ashx?tb=false&amp;id=

<%# Eval(“Id”) %>

target=”_blank”>

<img

alt=”<%# Eval(“Description”) %>

id=”tb_<%# Eval(“Id”) %>

src=”../WebStorageHandler.ashx?tb=true&amp;id=

<%# Eval(“Id”) %> />

</a><br />

<asp:ImageButton

ID=”EditButton”

runat=”server”

ImageUrl=”~/Images/edit.png”

Style=”border: none;

AlternateText=”Modify”

CommandName=”Modify”

CommandArgument=’<%# Eval(“Id”) %> />

</p>

<br />

</td>

</ItemTemplate>

In our code-behind, we’ve attached to our LINQ data source, so simple Eval statements return the item-specific data to the ListView.  The ImageButton, which we’ll discuss later in the Admin tools post, allows editing of the photo on the fly.

So, what’s this look like when rendered?

<table id=”ctl00_PageBody_lv_gPhC”
class=”galleryList” style=”width: 100%”>

<tr id=”ctl00_PageBody_lv_ctrl0_iPhC”>

<td id=”ctl00_PageBody_lv_ctrl0_ctl01_i”
class=”galleryItem” style=”vertical-align: top;”>

       <p><strong>Fallingstar</strong><br />

<a href=”../WebStorageHandler.ashx?tb=false&amp;id=42″
target=”_blank”>

<img alt=”Valefor, White Mage/Bard” id=”tb_42″
src=”../WebStorageHandler.ashx?tb=true&amp;id=42″ />

       </a><br /></p><br />

</td>

</table>

Simple, clean HTML.

Simple, clean layout

There’s one last bit of business now—tying up the events previously described for the ListView—PagePropertiesChanged, ItemCommand, and ItemCreated.

ItemCreated fires everytime a data item is bound to the list view, or, everytime an iPh is filled. Since our “edit” icon appears at every item, we only want that to appear to Administrators, so on each ItemCreated, check to see if the user’s an administrator and hide/show the button.

protected void lv_ItemCreated(object sender,

  ListViewItemEventArgs e)

{

if (e.Item.ItemType == ListViewItemType.DataItem)

e.Item.FindControl(“EditButton”).Visible =

Page.User.IsInRole(“Administrators”);

}

(We can cheat a bit here, since IsInRole returns true/false, we can use at as the toggle.  Be sure to check that the ListViewItemType is a DataItem—our EmptyItemTemplate doesn’t contain an “EditButton” control and will throw a null reference exception.

PagePropertiesChanged fires whenever the DataPager changes pages.  In our code behind, I’m simply rebinding the data source after the DataPager requests 12 new fields.

ItemCommand fires whenever a Command-enabled control, specifically our EditButton, is fired.  In this example, “Modify” will toggle the administration tools (which will be discussed in later posts).

protected void lv_ItemCommand(object sender,

ListViewCommandEventArgs e)

{

switch (e.CommandName)

{

       case “Modify”:

              ModifyCommand(

Convert.ToInt32(e.CommandArgument));

       break;

       default:

              break;

}

}

That’s it for now.  In the next post, I’ll discuss how the administration tools and “EditButton” operate on the Show galleries page.  Remember to check the Introduction post for source code updates.

%d bloggers like this: