A few days ago I wrote a post on how to create a fully dynamic Link class in C# that will return a full query string based on what a user is clicking within a page. In the following example I'll present the table design, Stored Procedure, C# class, CSS Class and ASP.NET user control I'm using to
1- Present a Data List control in a user control that uses an Item Template with a HyperLink control inside that dynamically chooses its NavigateURL, Text, ToolTip and CssClass values directly from ASP.NET to a business tier.
2- Generate a Query String
The following is the SQL Table I'm using for this example:
The following is the Stored Procedure I'm using to retrieve the data
ALTER PROCEDURE [dbo].[CatalogGetCategoryDetails](@CategoryID INT)AS
SELECT DepartmentID, Name, Description FROM CategoryWHERE CategoryID = @CategoryID
SELECT DepartmentID, Name, Description FROM CategoryWHERE CategoryID = @CategoryID
The following is the C# Class to generate the Query Strings (This class in within the App_Code folder in my project)
In the above code I'm calling the Link.ToCategory class (shown above) directly from ASP.NET.
NavigateUrl='<%# Link.ToCategory(Request.QueryString["DepartmentID"], Eval("CategoryID").ToString()) %>'
Also, if the CategoryID of the page is the same as the value requested in the Query String, then the Css Class named CategorySelected will be apply to the HyperLink control , otherwise the control will use the CategoryUnselected one:
CssClass = '<%#Eval(CategoryID).ToString() == Request.QueryString["CategoryID"] ? "CategorySelected" : "CategoryUnselected" %>'>
Because in my project the Product Categories are dependent on the Department that is being clicked, when the page is loading I need to always know the DepartmentID. If there is no Department ID when the Query String is requested, then no Categories will show.
Also, if the DepartmentID is not null, I need to set the DataList DataSource value (which will access my business tier class and the business tier will access the data base StoredProcedure shown above), and bind the data to the control as shown below:
The Following is the ASP.NET Using Control code
And the code behind:
NavigateUrl='<%# Link.ToCategory(Request.QueryString["DepartmentID"], Eval("CategoryID").ToString()) %>'
Also, if the CategoryID of the page is the same as the value requested in the Query String, then the Css Class named CategorySelected will be apply to the HyperLink control , otherwise the control will use the CategoryUnselected one:
CssClass = '<%#Eval(CategoryID).ToString() == Request.QueryString["CategoryID"] ? "CategorySelected" : "CategoryUnselected" %>'>
Because in my project the Product Categories are dependent on the Department that is being clicked, when the page is loading I need to always know the DepartmentID. If there is no Department ID when the Query String is requested, then no Categories will show.
Also, if the DepartmentID is not null, I need to set the DataList DataSource value (which will access my business tier class and the business tier will access the data base StoredProcedure shown above), and bind the data to the control as shown below:
using System;
using System.Collections.Generic;
using System.Web;
/// <summary>
/// Summary description for Link
/// </summary>
public class Link
{
public Link()
{
//
// TODO: Add constructor logic here
//
}
//Builds an absolute URL
private static string BuildAbsolute(string relativeUri)
{
//Get current Uri
Uri uri = HttpContext.Current.Request.Url;
//Build absolute path
string app = HttpContext.Current.Request.ApplicationPath;
if (!app.EndsWith("/")) app += "/";
relativeUri = relativeUri.TrimStart('/');
//Return the absolute path
return HttpUtility.UrlPathEncode(String.Format("http://{0}:{1}{2}{3}", uri.Host, uri.Port, app, relativeUri));
}
//Generate a department url
public static string ToDepartment(string departmentId, string page)
{
if (page == "1")
return BuildAbsolute(String.Format("Catalog.aspx?DepartmentID={0}", departmentId));
else
return BuildAbsolute(String.Format("Catalog.aspx?DepartmentID={0}&Page={1}", departmentId, page));
}
//Generate a department URL for the first page
public static string ToDepartment(string DepartmentId)
{
return ToDepartment(DepartmentId, "1");
}
public static string ToCategory(string departmentId, string categoryId, string page)
{
if (page == "1")
return BuildAbsolute(String.Format("Catalog.aspx?DepartmentID={0}&CategoryID={1}", departmentId, categoryId));
else
return BuildAbsolute(String.Format("Catalog.aspx?DepartmentID={0}&CategoryID={1}&Page={2}", departmentId, categoryId, page));
}
public static string ToCategory(string departmentId, string categoryId)
{
return ToCategory(departmentId, categoryId, "1");
}
public static string ToProduct(string productId)
{
return BuildAbsolute(String.Format("Product.aspx?ProductId{0}", productId));
}
public static string ToProductImage(string fileName)
{
//build product URL
return BuildAbsolute("/ProductImages/" + fileName);
}
}
The Following is the ASP.NET Using Control code
<%@ Control Language="C#" AutoEventWireup="true" CodeFile="CategoriesList.ascx.cs" Inherits="UserControls_CategoriesList" %>
<asp:DataList ID="list" runat="server" CssClass="CategoriesList" Width="200px">
<HeaderStyle CssClass="CategoriesListHead" />
<HeaderTemplate>
Choose a Category
</HeaderTemplate>
<ItemTemplate>
<asp:HyperLink ID="HyperLink1" Runat="server"
NavigateUrl='<%# Link.ToCategory(Request.QueryString["DepartmentID"], Eval("CategoryID").ToString()) %>'
Text='<%# HttpUtility.HtmlEncode(Eval("Name").ToString()) %>'
ToolTip='<%# HttpUtility.HtmlEncode(Eval("Description").ToString()) %>'
CssClass='<%# Eval("CategoryID").ToString() ==
Request.QueryString["CategoryID"] ?
"CategorySelected" : "CategoryUnselected" %>'>>
</asp:HyperLink>
</ItemTemplate>
</asp:DataList>
And the code behind:
using System;
using System.Collections.Generic;
using System.Linq;
using System.Web;
using System.Web.UI;
using System.Web.UI.WebControls;
public partial class UserControls_CategoriesList : System.Web.UI.UserControl
{
protected void Page_Load(object sender, EventArgs e)
{
//Obtain the ID of the selected Department
string departmentID = Request.QueryString["DepartmentID"];
//continue only if DepartmentID exists in the query string
if (departmentID != null)
{
//Catalog.GetCategoriesInDepartment returns a DataTable
//object containing the data, which will be displayed in the
//data list
list.DataSource = CatalogAccess.GetCategoriesInDepartment(departmentID);
//bind the datalist control
list.DataBind();
}
}
}
The following is my business tier class that resolves the GetCategoriesInDepartment
public static DataTable GetCategoriesInDepartment(string departmentId)
{
//Get a configured DbCommand object
DbCommand comm = GenericDataAccess.CreateCommand();
//Set stored procedure name
comm.CommandText = "CatalogGetCategoriesInDepartment";
//Create a new parameter
DbParameter param = comm.CreateParameter();
param.ParameterName = "@DepartmentID";
param.DbType = DbType.Int32;
comm.Parameters.Add(param);
//Execute the stored procedure
return GenericDataAccess.ExecuteSelectCommand(comm);
}
The above method in my business tier class calls another class in the business tier that handles Data Base related operations such as create and execute commands. The class below handles both of the commands
using System;
using System.Collections.Generic;
using System.Web;
using System.Data;
using System.Data.Common;
/// <summary>
/// Class contains generic data access to be accessed from the BusinessTier
/// </summary>
public static class GenericDataAccess
{
//Executes a command and returns the results as a DataTable object
public static DataTable ExecuteSelectCommand(DbCommand command)
{
//DataTable object to be return
DataTable table;
//Execute the command, making sure the connection will be always closed
try
{
//Open the data connection
command.Connection.Open();
//Execute the command and save the results into the DataTable object
DbDataReader reader = command.ExecuteReader();
table = new DataTable();
table.Load(reader);
//CLose the reader
reader.Close();
}
catch (Exception ex)
{
Utilities.LogError(ex);
throw;
}
finally
{
//Close the connection
command.Connection.Close();
}
return table;
}
//Creates and prepares a nre DbCommand object on a new connection
public static DbCommand CreateCommand()
{
//Get database provider name
string dataProviderName = null;
try
{
//string dataProviderName = BalloonShopConfiguration.DbProviderName;
dataProviderName = BalloonShopConfiguration.DbProviderName;
}
catch (Exception ex)
{
ex.InnerException.ToString();
}
//Get the database connection string
string connectionString = BalloonShopConfiguration.DbConnectionString;
//Create a new data provider factory
DbProviderFactory factory = DbProviderFactories.GetFactory(dataProviderName);
//Get a database specific connection object
DbConnection conn = factory.CreateConnection();
//Set the connection string
conn.ConnectionString = connectionString;
//Create a database specific command object
DbCommand comm = conn.CreateCommand();
//Set the command type to stored procedure
comm.CommandType = CommandType.StoredProcedure;
//retun the initialized command object
return comm;
}
}
NOTE: Just remember that the class above uses a Web.Config value for the connection string. You will have to create your own, but below there is an example:
<connectionStrings>
<add name="Connection" connectionString="Data Source=Server; Database=DataBaseName; user=username; Password=password" providerName="System.Data.SqlClient"/>
</connectionStrings>
Finally, the following is the CSS code that will make the HyperLink control change styles depending on the categoryId being different to the Query String value retrieved (this is explained above)
.CategoriesList {
border: #ea6d00 1px solid;
text-align: center;
margin-top: 20px;
}
.CategoriesListHead {
border: #ea6d00 1px solid;
background-color: #f8c78c;
}
a.CategoryUnselected {
line-height: 25px;
text-decoration: none;
color: Black;
}
a.CategoryUnselected:hover {
text-decoration: underline;
}
a.CategorySelected {
line-height: 25px;
font-weight: bold;
text-decoration: none;
color: Black;
}
.CatalogTitle {
color: red;
font-size: 24px;
font-weight: bold;
}
.CatalogDescription {
color: Black;
font-weight: bold;
font-size: 14px;
}
Happy programming!}
No comments:
Post a Comment
Thank you for your thoughts. Your comment will appear in my blog shortly after review.
Have a great day!