aDEFWEBSERVER
Los Angeles, CA *
 Webmaster@ADefWebserver.com

Back to: Creating a DotNetNuke® Module using LINQ to SQL For absolute beginners! Part 3

Use a ListView to implement grouping

 
The task presented in this section of the tutorial is to create a ListView that groups items by category.

This is done with two ListViews. The "outer" ListView shows each category while the "inner" ListView shows the items for each category.

A panel control hides the items for each category until the "+" is clicked.
   

Create the "grouping" LinqDataSource

 
Drag the LinqDataSource control to the design surface of the View.ascx page. Click on the options (right-arrow on the right side of the control) and select Configure Data Source.  
In the Configure Data Source box, select LinqThings4Sale.LinqThings4SaleDataContext in the drop-down and click the Next button.   

The Configure Data Selection screen will show.

  • Set Category for GroupBy
  • Enter Key asc for OrderGroupBy
  • In the third row in the grid, select Count for Column, Count for Function, and Count for Alias
 
Click the Where button.   

On the Configure Where Expression screen:

  • Select ModuleId in the Column drop-down
  • Select = = in the Operator drop-down
  • Select None for the Source drop-down
  • Enter 0 for Value

Click the Add button.

Click the OK button.

Click the Finish button.


In the properties for the LinqDataSource control, rename the ID to LDSGrouping

 


In the events for the LinqDataSource control enter LDSGrouping_Selecting for Selecting.

Create the ListView 

 
Drag a ListView control from the Toolbox and place it under the LinqDataSource control.

On the options for the ListView control, select LDSGrouping from the Choose Data Source drop-down. 
 
Switch to source view and replace:

<asp:ListView ID="ListView1" runat="server" DataSourceID="LDSGrouping">
</asp:ListView> 
 
With:   
<asp:ListView ID="LVGroup" runat="server" DataSourceID="LDSGrouping" OnItemDataBound="LVGroup_ItemDataBound">
<LayoutTemplate>
<table runat="server">
<tr runat="server">
<td runat="server">
<table id="itemPlaceholderContainer" runat="server" border="0" style="" class="ModuleTitle_MenuItem" cellpadding="5" cellspacing="5">
<tr id="Tr1" runat="server" style="">
<th id="Th1" runat="server">
</th>
<th id="Th6" runat="server">
Description
</th>
<th id="Th7" runat="server">
Price
</th>
</tr>
<tr id="itemPlaceholder" runat="server">
</tr>
</table>
</td>
</tr>
<tr runat="server">
<td runat="server" style="">
<asp:DataPager ID="DataPager1" runat="server" PageSize="4">
<Fields>
<asp:NextPreviousPagerField ButtonType="Button" ShowFirstPageButton="True" ShowLastPageButton="True" />
</Fields>
</asp:DataPager>
</td>
</tr>
</table>
</LayoutTemplate>
<ItemTemplate>
<tr id="row" runat="server" class="group">
<th colspan="1" width="50px" align="center" bgcolor="#CCCCCC">
<asp:LinkButton ID="MinMax" runat="server" OnClick="MinMax_Click" Text="+" CommandArgument='<%# Eval("Category") %>'></asp:LinkButton>
</th>
<th colspan="6" align="left" bgcolor="#CCCCCC">
<b>
<%# Eval("Category")%></b> -
<%# Eval("Count") %>
Item(s)
</th>
</tr>
<asp:Panel ID="pnlItems" runat="server" Visible="false">
<asp:ListView ID="lvItems" runat="server" OnItemDataBound="lvItems_ItemDataBound"
DataSource='<%# Eval("ThingsForSales") %>'>
<LayoutTemplate>
<tr runat="server" id="itemPlaceholder" />
</LayoutTemplate>
<ItemTemplate>
<tr style="">
<td align="center">
<asp:LinkButton ID="lnkSelect" runat="server" OnClick="lnkSelect_Click" CommandName='<%# Eval("ID") %>'
CommandArgument='<%# Eval("UserID") %>'>Select</asp:LinkButton>
</td>
<td>
<asp:Label ID="DescriptionLabel" runat="server" Text='<%# Eval("Description") %>' />
</td>
<td>
<asp:Label ID="PriceLabel" runat="server" Text='<%# Eval("Price", "{0:c}") %>' />
</td>
</tr>
</ItemTemplate>
</asp:ListView>
</asp:Panel>
</ItemTemplate>
</asp:ListView> 
Switch back to design view and the grid will resemble the image to the right.   

The ListView Explained 

 
   
See this article for an excellent overview of the ListView control:
http://msdn2.microsoft.com/en-us/library/bb398790.aspx
 
In this example the ListView contains a template (between the <LayoutTemplate> and </LayoutTemplate> tags). This determines the design of the control.

The LayoutTemplate also contains a DataPager that displays the paging buttons.

The remaining part of the control is in the ItemTemplate (between the <ItemTemplate> and </ItemTemplate> tags).
 

Inside the ItemTemplate another ListView control is defined. It's DataSource is set to Eval("ThingsForSales") which represents the items for each category.
 

<asp:Panel ID="pnlItems" runat="server" Visible="false">
<
asp:ListView ID="lvItems" runat="server" OnItemDataBound="lvItems_ItemDataBound" DataSource='<%# Eval("ThingsForSales") %>'>

<
LayoutTemplate>
<
tr runat="server" id="itemPlaceholder" />
</
LayoutTemplate>

<
ItemTemplate>
<
tr style="">
<
td align="center">
<
asp:LinkButton ID="lnkSelect" runat="server" OnClick="lnkSelect_Click" CommandName='<%# Eval("ID") %>' CommandArgument='<%# Eval("UserID") %>'>Select</asp:LinkButton>
</
td>
<
td>
<
asp:Label ID="DescriptionLabel" runat="server" Text='<%# Eval("Description") %>' />
</
td>
<
td>
<
asp:Label ID="PriceLabel" runat="server" Text='<%# Eval("Price", "{0:c}") %>' />
</
td>
</
tr>
</
ItemTemplate>

</
asp:ListView>
</
asp:Panel>

The ListView is contained inside a Panel control (pnlItems) that will hide and show the ListView  

The Code behind

 
Open the View.ascx.cs file and add the following code:  
 #region LinqDataSource
protected void LDSGrouping_Selecting(object sender, LinqDataSourceSelectEventArgs e)
{
e.WhereParameters["ModuleId"] = ModuleId;
}
#endregion
This code inserts the current ModuleId parameter so that the LinqDataSource control only displays data for the current module instance.

Add the following code:
 
 #region ViewState
[Serializable]
public class Category
{
public string Name { get; set; }
}

public List<Category> Categories
{
get
{
if (ViewState["Categories"] == null)
{
return new List<Category>();
}
else
{
return (List<Category>)ViewState["Categories"];
}
}
set
{
ViewState["Categories"] = value;
}
}
#endregion

This code exposes a Categories property that will be used to hold the categories that should be displayed in the "expanded" state. Categories that should be expanded are added to the list. Categories that should be "rolled up" are removed from the list.
 

Add the following code:
 
 #region ListView
protected void lvItems_ItemDataBound(object sender, ListViewItemEventArgs e)
{
LinkButton LinkButton = (LinkButton)e.Item.FindControl("lnkSelect");

if ((!PortalSecurity.IsInRole("Administrators"))
& !(Entities.Users.UserController.GetCurrentUserInfo().UserID == Convert.ToInt16(LinkButton.CommandArgument)))
{
e.Item.Controls[1].Visible = false;
}
}

protected void LVGroup_ItemDataBound(object sender, ListViewItemEventArgs e)
{
Panel Panel = (Panel)e.Item.FindControl("pnlItems");
LinkButton objLinkButton = (LinkButton)e.Item.FindControl("MinMax");

var results = from cat in Categories
where cat.Name == objLinkButton.CommandArgument
select cat;

if (results.Count() != 0)
{
Panel.Visible = true;
objLinkButton.Text = "-";
}
}
#endregion


This code adds two methods that fire each time a record is bound to each of the ListViews.

lvItems_ItemDataBound determines if the item belongs to the current user or if the current user is an Administrator. If either of these is true then the Select link for the record is made visible.

LVGroup_ItemDataBound determines if the category for the current record is in the Categories list. If it is then the panel control is made visible and the "+" is changed to a "-".

Add the following code:
 
 #region MinMax
protected void MinMax_Click(object sender, EventArgs e)
{
LinkButton objLinkButton = (LinkButton)sender;

var results = from cat in Categories
where cat.Name == objLinkButton.CommandArgument
select cat;

if (objLinkButton.Text == "+")
{
// Only add this category if it does not already exist
if (results.Count() == 0)
{
// Add the Category
Category objCategory = new Category { Name = objLinkButton.CommandArgument };
List<Category> colCategories = Categories;
colCategories.Add(objCategory);
Categories = colCategories;
}
}
else
{
// Only remove this category if it already exists
if (results.Count() != 0)
{
// Remove the Category
List<Category> colCategories = Categories;
Category objCategory = (Category)colCategories.FirstOrDefault(c => c.Name == objLinkButton.CommandArgument);
colCategories.Remove(objCategory);
Categories = colCategories;
}
}

LVGroup.DataBind();
}
#endregion



This code adds the category to the Categories list (stored in view state) if the link CommandArgument is set to "+".

It removes the category from the Categories list if the link CommandArgument is set to "-".

Add the following code:
 
 protected void lnkSelect_Click(object sender, EventArgs e)
{
LinkButton objLinkButton = (LinkButton)sender;

Response.Redirect(Globals.NavigateURL(PortalSettings.ActiveTab.TabID, "EditItem", "mid=" + ModuleId.ToString(), "RecordID=" + objLinkButton.CommandName));
}
This code fires when the Select link is clicked for an item and navigates to the edit page.
 
Save the file. From the Toolbar, select Build then Build Page. The page should build without errors.

The module is complete.
   
   

Back to: Creating a DotNetNuke® Module using LINQ to SQL For absolute beginners! Part 3



Buy DotNetNuke Modules from Snowcovered
 
(C) by Michael Washington - ADefWebserver.com - Webmaster@ADefWebserver.com

DotNetNuke® is a registered trademark of the DotNetNuke Corporation