65.9K
CodeProject 正在变化。 阅读更多。
Home

ASP.NET 电子商务 GridView 与产品比较

starIconstarIconstarIconstarIcon
emptyStarIcon
starIcon

4.86/5 (20投票s)

2010 年 9 月 27 日

CPOL

5分钟阅读

viewsIcon

103094

downloadIcon

6295

演示了带有产品比较复选框、排序、数据库中的图像、可展开/折叠的产品摘要、可选行显示和产品比较页面的电子商务风格网格。

引言

如今,电子商务 Web 应用程序随处可见,其中许多共享一套常见的功能。在本文中,我将展示如何使用 GridViewListView 控件来构建一个强大的产品页面,其中包含当今电子商务网站中的许多功能。我们将使用一些免费的剪贴画自行车图像来构建一个自行车商店产品网格。示例文件是用户控件,可以轻松添加到页面中。我们只使用三个图像来保持示例应用程序的大小较小。

Product Grid

背景

本文假定读者对使用 ObjectDataSource 控件进行 GridViewListView 控件的数据绑定有一定的了解。

数据库

需要产品比较的产品页面至少需要三个表:一个用于保存产品数据,另外两个用于支持产品比较功能。在此示例中,产品图像存储在数据库中,并使用图像处理程序进行检索。必须从应用程序中将图像插入数据库表中;您不能从 SQL 控制台将图像添加到表中。示例项目包含一个控制台应用程序,该应用程序会将三个图像放入数据库。通常,至少需要两个图像:一个用于网格和比较页面的小图像,以及一个用于产品详细信息页面的大图像。其余的表行将包含您想要的任何产品详细信息信息。

产品比较功能需要两个表:一个用于保存唯一的键以区分会话,另一个用于保存与唯一键关联的用户选定项。域层代码使用 ADO.NET 调用存储过程来显示带分页的产品。产品比较通过 JavaScript 处理,该 JavaScript 会计算所有已勾选的复选框,创建一个 Cookie 来保存它们,并使用 ID 查询字符串调用比较页面。比较页面上的 ObjectDataSource 具有一个指向页面加载时调用的方法的 "SelectMethod" 属性。ObjectDataSource.Select 方法调用存储过程来检索已比较产品的相关信息,并在项计数超过 ListViewGroupItemCount 时处理项的分页。要运行示例,请先执行 SQL Server 中 DatabaseImageInsert 项目 "Database Script" 文件夹中的数据库脚本 "BicycleDatabase.sql"。然后将 DatabaseImageInsert 项目设置为启动项目并执行它。这将把产品图像放入数据库。

数据库图像应用程序

有许多示例展示了如何从磁盘选择图像并将其存储在数据库中。我发现该方法的代码在直接从目录读取图像时不起作用;也就是说,我无法通过图像处理程序将图像读回。从磁盘读取图像需要实例化一个 Bitmap 对象并将其读入 MemoryStream。从 Stream 中,您可以获得一个字节数组,该字节数组将传递给 SqlCommand 对象。

产品网格

产品网格使用 GridView 和用户控件中实现的 ObjectDataSource。我们必须在域类中为 SelectCountMethodSelectMethod 实现两个方法。网格将支持分页和排序,因此这些属性设置为 true。我们将 DataKeyNames 设置为 ProductID,即数据源的主键字段,并将 DataSourceID 设置为 ObjectDataSource 的 ID。img 元素由一个图像处理程序填充,该程序接收项的 ProductID

<%@ Control Language="C#" AutoEventWireup="true" CodeBehind="ProductGrid.ascx.cs" 
       Inherits="eCommerceProductGrid.UserControls.ProductGrid" %>
<%@ Register assembly="System.Web.Extensions, Version=3.5.0.0, 
            Culture=neutral, PublicKeyToken=31bf3856ad364e35" 
       namespace="System.Web.UI.WebControls" tagprefix="asp" %>

<div style="float: left;">
  <asp:Label ID="PageResultsLabel" CssClass="resultPage" runat="server" 
    Width="100%" EnableViewState="False"></asp:Label>
</div>
<br />
<div style="padding-top: 5px; padding-bottom: 5px;">
  <asp:Button ID="btnCompare" runat="server" CssClass="buttonStyle" 
      Text="Compare Checked Items" Height="25" Width="190" EnableViewState="False" />
  <asp:Label ID="ComparisonError" runat="server" OnLoad="ComparisonError_Load" 
      CssClass="errorMessage" EnableViewState="False" />
    <div style="float: right; margin-right: 20%; border: 1px solid black;">
      <asp:DropDownList ID="GridPageNumberList" runat="server" Enabled="true" 
           AutoPostBack="True" 
           OnSelectedIndexChanged="GridPageNumberList_SelectedIndexChanged">
        <asp:ListItem Value="5">Display 5 per page</asp:ListItem>
        <asp:ListItem Value="7">Display 7 per page</asp:ListItem>
      </asp:DropDownList>
  </div>
</div>

<asp:ObjectDataSource ID="SourceBicycles"
                      runat="server"
                      EnablePaging="True"
                      SelectCountMethod="CountBicycles"
                      SelectMethod="GetBicycleGridDetails"
                      SortParameterName="SortExpression"
                      TypeName="eCommereProductGrid.Domain.BicycleProductDB">
</asp:ObjectDataSource>

<asp:GridView ID="gridBicycles"
              runat="server"
              AllowPaging="True"
              AllowSorting="True"
              AutoGenerateColumns="False"
              BackColor="White"
              CellPadding="0"
              DataKeyNames="ProductID"
              DataSourceID="SourceBicycles"
              EmptyDataText="No data returned from query"
              EnableViewState="false"
              Font-Names="Verdana"
              Font-Size="Small"
              GridLines="Horizontal"
              OnDataBound="GridBicycles_DataBound"
              OnPageIndexChanging="GridBicycles_PageIndexChanging" 
              OnRowDataBound="GridBicycles_RowDataBound"
              PageSize="5"
              Width="80%">
  <FooterStyle BackColor="GhostWhite" BorderColor="Gainsboro" ForeColor="Blue" />
  <HeaderStyle BackColor="GhostWhite" BorderColor="Gainsboro" 
      ForeColor="Blue" HorizontalAlign="Center" VerticalAlign="Middle" />
  <PagerSettings Position="TopAndBottom" FirstPageText="First" 
      LastPageText="Last" Mode="NumericFirstLast" />
  <PagerStyle BackColor="GhostWhite" BorderColor="Gainsboro" 
      ForeColor="Black" HorizontalAlign="Center" VerticalAlign="Middle"/>
  <RowStyle BackColor="White" ForeColor="Black" />

  <Columns>
    <asp:BoundField DataField="ProductID" />

    <asp:TemplateField ItemStyle-HorizontalAlign="Center" ItemStyle-VerticalAlign="Middle">
      <ItemTemplate>
        <input type="checkbox" id="checkBox" name="myCheckBox" runat="server" onclick="" 
                value='<%# DataBinder.Eval(Container.DataItem, "ProductID") %>' />
        <br />
        <b>Compare</b>
      </ItemTemplate>
      <ItemStyle HorizontalAlign="Center" VerticalAlign="Middle" Width="65px" />
    </asp:TemplateField>

    <asp:TemplateField>
      <ItemTemplate>
        <div style="padding-left: 15px; padding-right: 15px;">
          <a href='<%# DataBinder.Eval(Container.DataItem, 
                 "ProductGridLinkPage") %>?ProductID=
                 <%# DataBinder.Eval(Container.DataItem, "ProductID") %>'>
              <img src='DatabaseImageHandler.ashx?ID=<%# Eval("ProductID") %>' 
                 alt='<%# DataBinder.Eval(Container.DataItem, "BrandName") %> 
                      <%# DataBinder.Eval(Container.DataItem, "ModelName") %>'
                 border="0" />
          </a>
        </div>
      </ItemTemplate>
    </asp:TemplateField>

    <asp:TemplateField HeaderText="Sort" SortExpression="LinkTitle">
      <ItemTemplate>
        <table>
          <tr>
            <td>
              <a href='<%# DataBinder.Eval(Container.DataItem, 
                 "ProductGridLinkPage") %>;?productID=<%# DataBinder.Eval(
                    Container.DataItem, "ProductID") %>'>
              <%# DataBinder.Eval(Container.DataItem, "LinkTitle")%>
            </td>
          </tr>
          <tr>
            <td>
              <div id="summary" runat="server">
                <div id="expandedDiv" runat="server" style="display: none">
                  <asp:Label ID="summaryExpanded" Runat="server" 
                        Text='<%# Eval("Summary") %>'></asp:Label>
                </div>
                <div id="collapsedDiv" runat="server">
                  <asp:Label ID="summaryCollapsed" Runat="server" 
                       Text='<%# Eval("Summary") %>'></asp:Label>
                </div>
                <span id="genericControl" runat="server"></span>
            </div>
            </td>
          </tr>
          <tr>
              <td>
                <asp:Label ID="standardCost" Runat="server" 
                   CssClass="gridStandardPrice" 
                   Text='<%# Eval("MSRP", "Price: {0:C}") %>'></asp:Label>
              </td>
          </tr>
          <tr>
              <td>
                <asp:Label ID="listPrice" Runat="server" 
                  Text='<%# Eval("ListPrice", "MSRP: {0:C}") %>'></asp:Label>
              </td>
          </tr>
        </table>
      </ItemTemplate>
    </asp:TemplateField>
  </Columns>
</asp:GridView>

ProductGridPage_Load 事件调用 JavaScript 函数 getCheckedBoxes(),该函数收集已勾选的 CheckBox 的 ID 并将它们存储在 Cookie 中。Compare 按钮调用 JavaScript 函数 compareButtonClicked(),该函数从 Cookie 中读取已勾选的项,并使用每个已勾选项 ID 的查询字符串调用 ProductComparison.aspx 页面。GridViewRowDataBound 事件处理程序设置动态产品摘要文本 DIV 以进行展开和收缩。GridView DataBound 事件处理程序通过将 JavaScript 方法分配给 "Compare" 按钮并设置页码标签来设置所有产品比较所需的一切。

using System;
using System.Web.UI;
using System.Web.UI.HtmlControls;
using System.Web.UI.WebControls;
using eCommereProductGrid.Domain;

namespace eCommerceProductGrid.UserControls
{
    public partial class ProductGrid : UserControl
    {
        #region Fields
        private const string CHECKBOX_ATTRIBUTE = "ID";
        public const string CHECKBOX_STATE_SCRIPT = 
           "<script type='text/javascript'>getCheckedBoxes()</script>";
        public const string COMPARE_ITEMS_FUNCTION = "compareCheckedItems(this,'{0}')";
        public const string COMPARISON_RESULTS_TEXT = "Results {0} - {1} of {2}";
        private const int PRODUCT_SUMMARY_TEXT_WIDTH = 75;
        private int pagingIndex;
        #endregion

        #region Event Handlers
        protected void Page_Load(object sender, EventArgs e)
        {
            ClientScriptManager csm = Page.ClientScript;
            if (!csm.IsStartupScriptRegistered(GetType(), "CheckBoxState"))
            {
                csm.RegisterStartupScript(GetType(), "CheckBoxState",
                    CHECKBOX_STATE_SCRIPT);
            }
        }

        protected void GridPageNumberList_SelectedIndexChanged(object sender, EventArgs e)
        {
            gridBicycles.PageSize = Convert.ToInt32(GridPageNumberList.SelectedValue);
            gridBicycles.DataBind();
        }

        protected void ComparisonError_Load(object sender, EventArgs e)
        {   // Get a reference to the Comparison Error Message Label
        // to issue error message if less than 2 items are checked
            ComparisonError = sender as Label;
        }

        protected void GridBicycles_DataBound(object sender, EventArgs e)
        {
            foreach (GridViewRow row in gridBicycles.Rows)
            {
                // The ID column is necessary
                // for the comparisons checkbox. Remove it from view.
                row.Cells[0].Visible = false;
            }

            btnCompare.Attributes.Add("onclick", "compareButtonClicked();return false;");
            
            int maxRecords = GridRecordCount();
            int pageRecordCount = (pagingIndex + 1) * gridBicycles.PageSize;

            if (pageRecordCount > maxRecords)
            {
                pageRecordCount = maxRecords;
            }

            PageResultsLabel.Text = String.Format(COMPARISON_RESULTS_TEXT,
                pagingIndex * gridBicycles.PageSize + 1, pageRecordCount, maxRecords);
        }

        protected void GridBicycles_PageIndexChanging(object sender,
            GridViewPageEventArgs e)
        {
            pagingIndex = e.NewPageIndex;
        }

        protected void GridBicycles_RowDataBound(object sender, GridViewRowEventArgs e)
        {
            if (e.Row.RowType == DataControlRowType.DataRow)
            {
                TableCell cell = e.Row.Cells[2];
                Label summaryExpanded = (Label)cell.FindControl("summaryExpanded");
                HtmlGenericControl theCollapsedDiv = 
                   (HtmlGenericControl)cell.FindControl("collapsedDiv");
                HtmlGenericControl theExpandedDiv = 
                   (HtmlGenericControl)cell.FindControl("expandedDiv");

                string scriptCollapse =
                    "( <span class=\"caretback\">«</span><" + 
                    "script language="\""javascript\" type=\"text/javascript\">" +
                    "if(document.getElementById){document.writeln('<a " + 
                    "href=\"javascript:void(0)\" onclick=\"return" +
                    " toggleDisplay(' + \"'" + theCollapsedDiv.ClientID + 
                    "'\" + ')\"> less</a>');}</script>)";

                string summaryExpandedText = summaryExpanded.Text;
                summaryExpanded.Text = summaryExpandedText + scriptCollapse;

                Label summaryCollapsed = (Label)cell.FindControl("summaryCollapsed");
                string originalText = summaryCollapsed.Text;

                if (originalText.Length > PRODUCT_SUMMARY_TEXT_WIDTH)
                {
                    String text = originalText.Substring(
                        PRODUCT_SUMMARY_TEXT_WIDTH - 1, 15);
                    int indexOfFirstBlank = text.IndexOf(' ');
                    if (indexOfFirstBlank != -1)
                    {
                        string truncatedText = originalText.Substring(0, 
                               PRODUCT_SUMMARY_TEXT_WIDTH + indexOfFirstBlank - 1);
                        string scriptExpand = "( <span class=\"caret" + 
                            "back\">»</span><script language="\""javascript\" " +
                            "type=\"text/javascript\">if(document" + 
                            ".getElementById){document.writeln('<a" +
                            " href=\"javascript:void(0)\" onclick=\"return " + 
                            "toggleDisplay(' + \"'" +
                            theExpandedDiv.ClientID + "'\" + 
                            ')\"> more</a>');}</script>)";
                        summaryCollapsed.Text = truncatedText + "..." + scriptExpand;
                    }
                }
                HtmlGenericControl regGeneric = 
                  (HtmlGenericControl)cell.FindControl("genericControl");
                regGeneric.InnerHtml = 
                  "<script language="\""javascript\" type" + 
                  "=\"text/javascript\">registerToggle('" +
                  theCollapsedDiv.ClientID + "', '" + 
                  theExpandedDiv.ClientID.ToString() + "');</script>";

                // Add product ID to the row's checkBox so it can be uniquely identified
                HtmlInputCheckBox cb = (HtmlInputCheckBox)cell.FindControl("checkBox");
                eCommereProductGrid.Domain.BicycleProduct gp = 
                   (e.Row.DataItem as eCommereProductGrid.Domain.BicycleProduct);
                cb.Attributes.Add(CHECKBOX_ATTRIBUTE, gp.ProductID.ToString());
                cb.Attributes.Add("onclick", 
                   String.Format(COMPARE_ITEMS_FUNCTION, gp.ProductID));
            }
        }
        #endregion

        #region Properties
        #endregion

        #region Private Methods
        private int GridRecordCount()
        {
            return BicycleProductDB.CountBicycles();
        }
        #endregion
    }
}

当点击 Compare Items 按钮时,将调用函数 compareButtonClicked(),该函数创建一个 Cookie 来保存已勾选的 CheckBox

function createCookie(name, value, days)
{
    if (days) {
        var date = new Date();
        date.setTime(date.getTime()+(days*24*60*60*1000));
        var expires = "; expires="+date.toGMTString();
    }
    else {
        var expires = "";
    }
    document.cookie = name+"="+value+expires+"; path=/";
}

function getCookie(name)
{
    var nameFormatted = name+"=";
    var cookies = document.cookie.split(';');
    
    for(var i=0; i < cookies.length; i++) {
        var cookie = cookies[i];
        while (cookie.charAt(0) == ' ')
            cookie = cookie.substring(1, cookie.length);

        if (cookie.indexOf(nameFormatted) == 0)
            return cookie.substring(nameFormatted.length, cookie.length);
    }
    
    return null;
}

function compareCheckedItems(checkBox, itemno)
{
    var compareCookie = getCookie('compareCookie');
    var comparedItems = new Array();

    if (checkBox.checked == true) {
        if (compareCookie) {
            comparedItems = compareCookie.split(',');
            comparedItems.unshift(itemno);

            if (comparedItems.length > 12) {
                comparedItems.pop();
            }

            compareCookie = comparedItems.join(',');
            createCookie('compareCookie', compareCookie, 0);
        }
        else {
            createCookie('compareCookie', itemno, 0);
        }
    }
    else if (checkBox.checked == false) {
        comparedItems = compareCookie.split(',');

        for(var i = 0; i <= comparedItems.length-1; i++) 
        {
            if (comparedItems[i] == itemno) {
                comparedItems.splice(i,1);
                compareCookie = comparedItems.join(',');
                createCookie('compareCookie', compareCookie, 0);
            }
        }
    }
}

function compareButtonClicked()
{
    var compareCookie = getCookie('compareCookie');
    var isValidSelection = false;

    if (compareCookie) {
        var comparedItems = new Array();
        comparedItems = compareCookie.split(',');

        if (comparedItems.length > 1) {
            isValidSelection = true;
        }
    }

    if (isValidSelection) {
        var queryString = "";
        for (var i = 0; i < comparedItems.length; i++) {
            var item = "ID=" + comparedItems[i];
            if (i != comparedItems.length - 1)
                queryString = queryString + item + "&";
            else
                queryString = queryString + item;
        }

        if (document.domain == "localhost")
          window.location.href = 'https://:49625/ComparePage.aspx?' + 
                                 queryString;
        else
            window.location.href = 'http://' + document.domain + 
                                   '/ComparePage.aspx?' + queryString;
    }
    else
    {
        alert('Please select at least two items to compare.');
    }
}

function makeNewCookie() {
    var compareCookie = "";
    createCookie('compareCookie', compareCookie, 0);
}

function getCheckedBoxes() {
    var mc = getCookie('compareCookie');
    if (mc) {
        var checkedItems = new Array();
        checkedItems = mc.split(',');
        var checkBoxes = new Array();
        checkBoxes = document.getElementsByTagName('input');
        for (var i = 0; i <= checkedItems.length-1; i++) {
            for (var x = 0; x <= checkBoxes.length-1; x++) {
                if (checkedItems[i] == checkBoxes[x].value) {
                    checkBoxes[x].checked = true;
                }
            }
        }
    }
}

这是网格的 ObjectDataSource 的域类。BicycleProduct 类仅是一个具有重载构造函数和每个字段的自动 public 属性的类,为简洁起见在此省略。

using System.ComponentModel;
using System.Data;
using System.Data.SqlClient;
using System.Web.Configuration;
using System.Collections.Generic;

namespace eCommereProductGrid.Domain
{
    public class BicycleProductDB
    {
        public static int CountBicycles()
        {
            int nRows;
            using (SqlConnection connection = 
                new SqlConnection(WebConfigurationManager.
                    ConnectionStrings["BicycleDatabase"].ConnectionString))
            {
                SqlCommand command = connection.CreateCommand();
                command.Connection = connection;
                command.CommandType = CommandType.StoredProcedure;
                command.CommandText = "CountBicycleProducts";
                connection.Open();
                nRows = (int)command.ExecuteScalar();
            }
            return nRows;
        }

        [DataObjectMethod(DataObjectMethodType.Select, false)]
        public List<BicycleProduct> GetBicycleGridDetails(
                   string SortExpression, int startRowIndex, int maximumRows)
        {
            List<BicycleProduct> list = new List<BicycleProduct>();
            DataSet dataSet = new DataSet();

            using (SqlConnection connection = 
                   new SqlConnection(WebConfigurationManager.
                       ConnectionStrings["BicycleDatabase"].ConnectionString))
            {
                using (SqlCommand command = connection.CreateCommand())
                {
                    command.CommandType = CommandType.StoredProcedure;
                    command.CommandText = "GetAllProductsPaged";
                    command.Parameters.Add(new SqlParameter("@Start", SqlDbType.Int, 4));
                    command.Parameters["@Start"].Value = startRowIndex;
                    command.Parameters.Add(new SqlParameter("@Count", SqlDbType.Int, 4));
                    command.Parameters["@Count"].Value = maximumRows;
                    SqlDataAdapter adapter = new SqlDataAdapter(command);
                    connection.Open();
                    adapter.Fill(dataSet, "Bicycles");
                }
            }

            DataView view = dataSet.Tables[0].DefaultView;
            view.Sort = SortExpression;

            foreach (DataRowView row in view)
            {
                BicycleProduct displayDetails = new BicycleProduct(
                    (string) row["BrandName"],
                    (string)row["Color"],
                    (string)row["GridPageImageName"],
                    (string)row["LinkTitle"],
                    (decimal)row["ListPrice"],
                    (string)row["ModelName"],
                    (decimal)row["MSRP"],
                    (int)row["PercentSaved"],
                    (int)row["ProductID"],
                    (string)row["ProductPageImageName"],
                    (string)row["ProductGridLinkPage"],
                    (decimal)row["Savings"],
                    (string)row["Summary"],
                    (decimal)row["Weight"]);

                list.Add(displayDetails);
            }
            return list;
        }

        public static void GetProductDetailsFor(int ProductID, DataSet displaySet)
        {
            using (SqlConnection connection = 
                new SqlConnection(WebConfigurationManager.
                        ConnectionStrings["BicycleDatabase"].ConnectionString))
            {
                SqlCommand command = connection.CreateCommand();
                command.CommandType = CommandType.StoredProcedure;
                command.CommandText = "GetProductDetailsByProductID";
                command.Parameters.Add(new SqlParameter("@ProductID", SqlDbType.Int, 4));
                command.Parameters["@ProductID"].Value = ProductID;
                SqlDataAdapter adapter = new SqlDataAdapter(command);
                connection.Open();
                adapter.Fill(displaySet, "ProductDetails");
            }
        }
    }
}

我们的图像处理程序类接收要显示的项的 ID,从数据库中检索它,并将其提供给 GridView

using System;
using System.Configuration;
using System.Data;
using System.Data.SqlClient;
using System.IO;
using System.Web;

namespace eCommerceProductGrid
{
    public class DatabaseImageHandler : IHttpHandler
    {

        public void ProcessRequest(HttpContext context)
        {
            if (context.Request.QueryString["ID"] == null)
                throw new ArgumentException("No parameter specified");

            using (SqlConnection connection = 
                   new SqlConnection(ConfigurationManager.
                       ConnectionStrings["BicycleDatabase"].ConnectionString))
            {
                string sql = "SELECT GridPageImage, " + 
                   "ImageContentType FROM BicycleProduct WHERE ProductID=@ID";
                SqlCommand sqlCommand = new SqlCommand(sql, connection);
                sqlCommand.CommandType = CommandType.Text;
                sqlCommand.Parameters.Add("@ID", SqlDbType.Int, 4);
                sqlCommand.Parameters["@ID"].Value = context.Request.QueryString["ID"];

                connection.Open();
                SqlDataReader reader = sqlCommand.ExecuteReader(CommandBehavior.Default);
                reader.Read();

                try
                {
                    MemoryStream stream = new MemoryStream((
                        byte[])reader["GridPageImage"]);
                    byte[] buffer = new byte[stream.Length];
                    int byteSeq = stream.Read(buffer, 0, (int)stream.Length);
                    context.Response.ContentType = reader["ImageContentType"].ToString();

                    while (byteSeq > 0)
                    {
                        context.Response.OutputStream.Write(buffer, 0, byteSeq);
                        byteSeq = stream.Read(buffer, 0, (int)stream.Length);
                    }
                }
                catch (SqlException ex)
                {
                    context.Response.Write(ex.Message);
                }
                finally
                {
                    reader.Close();
                }
           }
        }
 
        public bool IsReusable
        {
            get
            {
                return false;
            }
        }
    }
}

产品比较页面

比较页面使用 ListView 和一个 ObjectDataSource,该 ObjectDataSourceGridView 相同,只是没有 SortParameterName 属性。ListView 设置为每页显示四项,并启用分页。

ComparisonGrid

<%@ Control Language="C#" AutoEventWireup="true" CodeBehind="ProductComparison.ascx.cs" 
         Inherits="eCommerceProductGrid.UserControls.ProductComparison" %>

<asp:ObjectDataSource ID="sourceBicycles"
                      runat="server"
                      EnablePaging="True"
                      SelectCountMethod="CountBicycles"
                      SelectMethod="CompareBicycleDetails"
                      TypeName="eCommereProductGrid.Domain.CompareBicycleProductsDB">
  <SelectParameters>
    <asp:QueryStringParameter Name="QueryValues" QueryStringField="ID" />
  </SelectParameters>
</asp:ObjectDataSource>

<asp:ListView ID="ListView"
              Runat="server"
              DataSourceID="sourceBicycles"
              GroupItemCount="4">
  <LayoutTemplate>
    <table id="LayoutTable" runat="server" border="1">
        <tr id="groupPlaceholder" runat="server">
        </tr>
    </table>
    <asp:DataPager runat="server" ID="ContactsDataPager" PageSize="4">
        <Fields>
          <asp:TemplatePagerField>
            <PagerTemplate>
              <div class="productComparisonPager">
                <b>
                Page
                <asp:Label runat="server" ID="CurrentPageLabel" Font-Size="Small"
                    Text="<%# Container.TotalRowCount>0 ? 
                    (Container.StartRowIndex / Container.PageSize) + 1 : 0 %>" />
                of
                <asp:Label runat="server" ID="TotalPagesLabel" Font-Size="Small"
                    Text="<%# Math.Ceiling ((double)Container.TotalRowCount / 
                                      Container.PageSize) %>" />
                <br />
                </b>
              </div>
            </PagerTemplate>
          </asp:TemplatePagerField>

          <asp:NumericPagerField PreviousPageText="< Prev 4" NextPageText="Next 4 >" />
        </Fields>
    </asp:DataPager>
  </LayoutTemplate>

  <GroupTemplate>
    <tr><td runat="server" id="itemPlaceholder" valign="top" /></tr>
  </GroupTemplate>

  <ItemTemplate>
    <td>
      <table class="comparisonTable" id="rptProduct" runat="server" border="0">
        <tr>
          <td style="height: 50px;font-size: small">
              <a href='<%# DataBinder.Eval(Container.DataItem, 
                 "ProductGridLinkPage") %>?productID=<%# DataBinder.Eval(
                 Container.DataItem, "ProductID") %>' />
              <%# DataBinder.Eval(Container.DataItem, "LinkTitle")%>  </td>
        </tr>
        <tr>
          <td style="height: 50px;">
            <a href='<%# DataBinder.Eval(Container.DataItem, 
                 "ProductGridLinkPage") %>?ProductID=<%# DataBinder.Eval(
                 Container.DataItem, "ProductID") %>' />
              <img src='DatabaseImageHandler.ashx?ID=<%# DataBinder.Eval(
                           Container.DataItem, "ProductID") %>'
                   alt="<%# DataBinder.Eval(Container.DataItem, 
                       "BrandName") %> <%# DataBinder.Eval(Container.DataItem, 
                       "ModelName") %>" border="0" />
          </td>
        </tr>
        <tr>
          <td><b>Brand:</b> <%# DataBinder.Eval(Container.DataItem, "BrandName")%></td>
        </tr>
        <tr>
          <td><b>Model:</b> <%# DataBinder.Eval(Container.DataItem, "ModelName")%></td>
        </tr>
        <tr>
          <td><b>Color:</b> <%# DataBinder.Eval(Container.DataItem, "Color")%></td>
        </tr>
        <tr>
          <td><b>Weight:</b> <%# DataBinder.Eval(Container.DataItem, "Weight")%></td>
        </tr>
        <tr class="comparisonPrice">
          <td><b>List Price:</b> 
            <%# DataBinder.Eval(Container.DataItem, "ListPrice", "{0:C}")%></td>
        </tr>
        <tr>
          <td><b>MSRP:</b> <%# DataBinder.Eval(Container.DataItem, "MSRP", "{0:C}")%>
	 </td>
        </tr>
        <tr>
          <td><b>Savings:</b> <%# DataBinder.Eval(Container.DataItem, "Savings", "{0:C}")%>
              (<%# DataBinder.Eval(Container.DataItem, "PercentSaved")%>%)</td>
        </tr>
        <tr>
          <td style="height: 35px" align="center">
            <asp:Button ID="RemoveItemButton" runat="server" CommandName="REMOVE"
                CommandArgument='<%# DataBinder.Eval(Container.DataItem, "ProductID") %>'
                 oncommand="ImageButton_Command" Text="Remove" />
          </td>
        </tr>
        <tr>
          <td style="height: 35px" align="center">
            <asp:Button ID="DisplayItemButton1" runat="server" CommandName="DISPLAY"
                CommandArgument='<%# DataBinder.Eval(Container.DataItem, "ProductID") %>'
                Text="Display" oncommand="ImageButton_Command" />
          </td>
        </tr>
        </tr>
      </table>
    </td>
  </ItemTemplate>
</asp:ListView>

代码隐藏中的 Page_Load 事件处理程序会解析查询字符串中的 ID 并进行存储,因此如果比较中有多于两项,用户可以删除它们。按钮单击处理程序仅执行给定的命令,例如删除项或显示项的产品页面。

using System;
using System.Collections.Generic;
using System.Collections.Specialized;
using System.Text;
using System.Web.UI.WebControls;
using System.Web.UI;
using eCommereProductGrid.Domain;

namespace eCommerceProductGrid.UserControls
{
    public partial class ProductComparison : UserControl
    {
        #region Fields
        private const string DISPLAY_ITEM = "DISPLAY";
        private const string REMOVE_ITEM = "REMOVE";
        private List<int> queryArgs = new List<int>();
        #endregion

        #region Event Handlers

        protected void Page_Load(object sender, EventArgs e)
        {
            NameValueCollection coll = Request.QueryString;
            String[] key = coll.AllKeys;

            for (int loop1 = 0; loop1 < key.Length; loop1++)
            {
                String[] value = coll.GetValues(key[loop1]);

                if (value != null && value.Length > 0)
                {
                    for (int ix = 0; ix < value.Length; ix++)
                    {
                        int id = Convert.ToInt32(Server.HtmlEncode(value[ix]));
                        queryArgs.Add(id);
                    }
                }
            }
        }

        protected void ImageButton_Command(object sender, CommandEventArgs e)
        {
            if (e.CommandName == DISPLAY_ITEM)
            {
                int productID = Convert.ToInt32(e.CommandArgument);
                string pageName = CompareBicycleProductsDB.GetProductPageName(productID);
                Response.Redirect("~/" + pageName + "?ProductID=" + productID, true);
            }
            else if (e.CommandName == REMOVE_ITEM)
            {
                if (ListView.Items.Count > 2)
                {
                    queryArgs.Remove(Convert.ToInt32((string)e.CommandArgument));
                    Response.Redirect("~/ComparePage.aspx?" + ParseQueryArgs());
                }
            }
        }

        #endregion

        #region Private Methods
        
        private string ParseQueryArgs()
        {
            StringBuilder query = new StringBuilder();

            foreach (int parm in queryArgs)
            {
                if (query.Length != 0)
                {
                    query.Append("&");
                }
                query.AppendFormat("ID={0}", parm);
            }
            return query.ToString();
        }
 
        #endregion
    }
}

运行示例代码

示例代码是一个 Visual Studio 2008 解决方案,并使用 SQL Server 2008。在 localhost 下执行解决方案时,localhost 使用的端口号必须与 JavaScript 函数 compareButtonClicked() 中执行比较页面的端口号相同。我在解决方案的属性中添加了端口 49625,但您的计算机可能需要不同的端口。如果是这样,请更改 Web 项目的属性以使用您的端口号,并更改 ProductComparison.js 的第 92 行以包含新端口号。

  1. 构建解决方案
  2. DatabaseImageInsert 项目设置为启动项目
  3. 在 SQL Server 中的 "Database Script" 文件夹中执行 SQL 脚本
  4. 执行 DatabaseImageInsert 项目
  5. eCommerceProductGrid 设置为启动项目并运行它
© . All rights reserved.