ASP.NET Web 表单:如何仅使用 C# 和 ASP.NET Web 表单在另一个页面的 table 上将 CheckBoxList 项引用为 'selected'?

ASP.NET Web Forms: How to reference CheckBoxList items as 'selected' on a table on another page using only C# and ASP.NET web forms?

赋值说明:

开发一个使用会话对象存储信息的简单购物车应用程序。您必须创建一个包含两个 Web 表单的 ASP.NET 项目。第一个 Web 表单 ShoppingCart.aspx 允许用户使用一组复选框来 select 项目。此页面还显示购物车中的商品数量。

第二个网络表单 Display.aspx 在 table 中显示 selected 项目的数量,并允许用户返回到第一个网络表单并继续购物。


如何引用第 1 页上 select 的复选框,这将在单击 'checkout' 后更新第 2 页上所需的 table 单元格列表项上没有唯一 ID 的按钮?

示例:如果...在第 1 页上 select 编辑了 1 磅深色烤... (下一页产品 1 标识为 'p001')

<asp:ListItem Value="15.99">1lb Dark Roast</asp:ListItem>

在第 2 页 (Display.aspx),该产品旁边的金额列应更新为“1”

<asp:TableCell ID="p001_amt" runat="server"></asp:TableCell>

如果某个项目在第 1 页上被选中,这应该是结果...(以及其他产品)。

Product Price Amount
1lb dark Roast .99 1
1lb Med Roast .99 0

1 = 选中,0 = 未选中(作业期望结果显示此 table)

如有任何帮助,我们将不胜感激。谢谢。


这是我的代码片段,如果需要更多,我可以在完整页面中添加 link。

第 1 页(ShoppingCart.aspx)

ShoppingCart.aspx
------------------
<asp:Label ID="TotalCart_lbl" runat="server" Text="Total Items in your Cart: "></asp:Label>
<br />
<asp:CheckBoxList ID="Shop_ckbx" runat="server">
                    <asp:ListItem Value="15.99">1lb Dark Roast</asp:ListItem>
                    <asp:ListItem Value="15.99">1lb Medium Roast</asp:ListItem>
                    <asp:ListItem Value="12.99">1lb Decaf Roast</asp:ListItem>
                    <asp:ListItem Value="16.99">1lb Cold Brew</asp:ListItem>
                    <asp:ListItem Value="10.99">1 box Tea</asp:ListItem>
                    <asp:ListItem Value="35.99">French Press</asp:ListItem>
                    <asp:ListItem Value="8.99">CCM Mug</asp:ListItem>
                </asp:CheckBoxList>
<br />
<asp:Button ID="UpdateCart_btn" runat="server" Text="Update Your cart" OnClick="UpdateCart_btn_Click"/>
<br />
<asp:Label ID="Contents_lbl" runat="server" Text="Update To See Cart Contents"></asp:Label>
<br />
<asp:Label ID="Cost_lbl" runat="server" Text="Total: "></asp:Label>
<br />
<asp:Button ID="Checkout_btn" runat="server" PostBackUrl="~/Display.aspx" Text="Go to Checkout" />

ShoppingCart.aspx.cs
---------------------
protected void UpdateCart_btn_Click(object sender, EventArgs e)
      {
         int total = 0; //Total item count

         Contents_lbl.Text = "Your Cart Contains: <br/>- - - - - - - - - - - - - - - -";
         
         foreach (ListItem listItem in Shop_ckbx.Items)
         {
            if (listItem.Selected == true)
            {
               //Add Text to label
               Contents_lbl.Text += "<br/>&#8226 " + listItem.Text;

               //Count Items in Cart
               total += 1;
            }
         }
         Contents_lbl.Text += "<br/>";

         for (int i = 0; i < Shop_ckbx.Items.Count; i++)
         {
            if (Shop_ckbx.Items[i].Selected)
            {
               cost += Convert.ToDouble(Shop_ckbx.Items[i].Value);
               Cost_lbl.Text = "Total: $ " + cost.ToString();
            }
         }
         //Update total items
         TotalCart_lbl.Text = "Total Items in Your Cart: " + total;
      }

protected void Checkout_btn_Click(object sender, EventArgs e)
      {
          How do I reference the items in the checklist on page 1 
          to update the table on page 2 without unique IDs on each list item?
      }


第 2 页代码 (Display.aspx)

Display.aspx
------------------
<asp:Table ID="Display_tbl" runat="server">
                <asp:TableRow runat="server" ID="Header_row" Font-Bold="True" Font-Size="Larger" BackColor="#FFCC99">
                    <asp:TableCell ID="Product_cell" runat="server" Width="250">Product</asp:TableCell>
                    <asp:TableCell ID="Price_cell" runat="server" Width="100">Price</asp:TableCell>
                    <asp:TableCell ID="Amount_cell" runat="server" Width="100">Amount</asp:TableCell>
                </asp:TableRow>
                <asp:TableRow runat="server" ID="p001">
                    <asp:TableCell ID="p001_prod" runat="server">1lb Dark Roast</asp:TableCell>
                    <asp:TableCell ID="p001_price" runat="server">$ 15.99</asp:TableCell>
                    <asp:TableCell ID="p001_amt" runat="server"></asp:TableCell>
                </asp:TableRow>
                <asp:TableRow runat="server" ID="p002" Width="500px">
                    <asp:TableCell ID="p002_prod" runat="server">1lb Med Roast</asp:TableCell>
                    <asp:TableCell ID="p002_price" runat="server">$ 15.99</asp:TableCell>
                    <asp:TableCell ID="p002_amt" runat="server"></asp:TableCell>
                </asp:TableRow>
                <asp:TableRow runat="server" ID="p003">
                    <asp:TableCell ID="p003_prod" runat="server">1lb Decaf</asp:TableCell>
                    <asp:TableCell ID="p003_price" runat="server">$ 12.99</asp:TableCell>
                    <asp:TableCell ID="p003_amt" runat="server"></asp:TableCell>
                </asp:TableRow>
                <asp:TableRow runat="server" ID="p004">
                    <asp:TableCell ID="p004_prod" runat="server">1lb Cold Brew</asp:TableCell>
                    <asp:TableCell ID="p004_price" runat="server">$ 16.99</asp:TableCell>
                    <asp:TableCell ID="p004_amt" runat="server"></asp:TableCell>
                </asp:TableRow>
                <asp:TableRow runat="server" ID="p005">
                    <asp:TableCell ID="p005_prod" runat="server">1 box Tea (50 bags)</asp:TableCell>
                    <asp:TableCell ID="p005_price" runat="server">$ 10.99</asp:TableCell>
                    <asp:TableCell ID="p005_amt" runat="server"></asp:TableCell>
                </asp:TableRow>
                <asp:TableRow runat="server" ID="p006">
                    <asp:TableCell ID="p006_prod" runat="server">French Press</asp:TableCell>
                    <asp:TableCell ID="p006_price" runat="server">$ 35.99</asp:TableCell>
                    <asp:TableCell ID="p006_amt" runat="server"></asp:TableCell>
                </asp:TableRow>
                <asp:TableRow runat="server" ID="p007">
                    <asp:TableCell ID="p007_prod" runat="server">CCM Coffee Mug</asp:TableCell>
                    <asp:TableCell ID="p007_price" runat="server">$ 8.99</asp:TableCell>
                    <asp:TableCell ID="p007_amt" runat="server"></asp:TableCell>
                </asp:TableRow>
                <asp:TableRow runat="server" ID="Total_row">
                    <asp:TableCell ID="Total_prod" runat="server">Total</asp:TableCell>
                    <asp:TableCell ID="Total_price" runat="server"></asp:TableCell>
                    <asp:TableCell ID="Total_amt" runat="server"></asp:TableCell>
                </asp:TableRow>
            </asp:Table>
            
<asp:LinkButton ID="Back_linkbtn" runat="server" OnClick="Back_linkbtn_Click">Go Back to the Shop</asp:LinkButton>


Display.aspx.cs
-------------------
protected void Page_Load(object sender, EventArgs e)
      {
         ShoppingCart prevPage = PreviousPage as ShoppingCart;
         if (prevPage != null) 
         {
              NOT SURE HOW TO LINK TO MY CHECKLIST ITEMS 
              TO UPDATE 'AMOUNT' TABLE CELLS
              
              Also,
              CHECKBOXES ON PREVIOUS PAGE NEED TO STAY SELECTED 
              in order to CONTINUE SHOPPING.
              
         } 
      }

protected void Back_linkbtn_Click(object sender, EventArgs e)
      {
         Response.Redirect("ShoppingCart.aspx");
      }


好的,所以我们这里的问题当然是匹配您在一个页面上 select 编辑的“东西”,然后在下一个网页上解决这个问题。

公平地说,这里的问题是你必须在这里“编造”数据。这真的伤害了整个过程,因为您必须输入两次数据(一次在此页面上,然后在目标页面上)。更糟糕的是,你必须通过“文本”来匹配。一点点 space、句点等等,你的整个系统就会崩溃。

我建议我们不要担心,也不必匹配这些值。我们可以一次性解决一个巨大的问题,还可以减少标记、代码和您生活中的所有麻烦(好吧,好吧,只是编码部分——不能解决所有问题!!!)。

因此,我建议创建一个 table 来代替复选框“列表”,并将其用于两个页面。这样一来,这不仅可以让我们远离带有软垫墙的房间,而且我们可以处理“一排”你 select 的东西,而不会对拼写甚至我们在其中放置的东西发出任何声音排。通过这样做,您几乎无需更改代码即可将“列表”从我们的 table 更改为数据库 - 并且整个 she-bang 都可以工作!

所以,让我们使用(创建)一个 table,这不仅简单,而且我认为设置我们的数据要干净得多。

所以,我们将在页面的开头有这个(一个 table 和整个页面的一些总值 class。

public class MyFirstOrderPage : System.Web.UI.Page
{
private DataTable MyTable = new DataTable();

private decimal MyTotal = 0;
private int MyTotalQty = 0;

好的,现在让我们在此页面中执行子操作以加载上面的 table。

public void CreateData()
{
    MyTable.Columns.Add("Product", typeof(string));
    MyTable.Columns.Add("Price", typeof(decimal));
    MyTable.Columns.Add("Qty", typeof(int));
    MyTable.Columns.Add("Amount", typeof(decimal));
    MyTable.Columns.Add("Purchased", typeof(bool));

    MyTable.Rows.Add({"11b Dark Roast",15.99,1,0,false});
    MyTable.Rows.Add({"11b Medium Roast",15.99,1,0,false});
    MyTable.Rows.Add({"1b Decaf Roast",12.99,1,0,false});
    MyTable.Rows.Add({"11b Cold Brew",16.99,1,0,false});
    MyTable.Rows.Add({"1 box Tea Brew",10.99,1,0,false});
    MyTable.Rows.Add({"French Press",35.99,1,0,false});
    MyTable.Rows.Add({"CCM Mug",8.99,1,0,false});
}

现在您不仅可以“轻松”阅读上面的内容,还可以 change/view 查看列,然后是数据 - 所以您可以看到我们决定有一个数量和一个列购买的。这将节省 BUCKETS 代码和 BUCKETS 标记。我们可以将以上内容用于两个页面 - 无需拥有此列表的两个副本!!!!

好的,现在我们有了 table。接下来,让我们显示 table。我们可以在订单页面中使用与在结帐页面中使用的网格非常相似的网格(节省更多时间、更多代码甚至更多标记!!!)。

所以,让我们使用 gridview。我们可以使用列表视图,如果您想要一张可爱的图片和更多的产品描述,我会考虑。但是,gridview 没问题。

因此,这是网格视图的标记:

<form id="form1" runat="server">
    <div>
        <asp:GridView ID="GridView1" runat="server" ShowFooter="true"
            Font-Bold="True" Font-Size="Larger" BackColor="#FFCC99" AutoGenerateColumns="False">

            <Columns>
                <asp:BoundField DataField="Product" HeaderText="Product" Headerstyle-width="250px" />
                <asp:BoundField DataField="Price" DataFormatString="{0:C2}" HeaderText="Price" Headerstyle-width="80px" />
                <asp:TemplateField HeaderText="Qty" >
                    <ItemTemplate>
                    <asp:TextBox ID="Qty" runat="server" Width="60px" 
                        Text ='<%# Eval("Qty") %>' 
                        MyRow = '<%# Container.DataItemIndex %>' 
                        AutoPostBack="true" OnTextChanged="Qty_TextChanged"
                      />
                    </ItemTemplate>
            </asp:TemplateField>

            <asp:TemplateField HeaderText="Amount">
                <ItemTemplate>
                    <asp:TextBox ID="Amount" runat="server" width="80px"
                        Text ='<%# FormatCurrency(Eval("Qty") * Eval("Price")) %>' Enabled="false" DataFormatString="{0:C2}"  />
                </ItemTemplate>
            </asp:TemplateField>

            <asp:TemplateField HeaderText="Purchase"  ItemStyle-HorizontalAlign="Center">
                <ItemTemplate >
                    <asp:CheckBox ID="CheckBox1" runat="server" width="110px" 
                        Checked ='<%# Eval("Purchased") %>' 
                        MyRow = '<%# Container.DataItemIndex %>' 
                        AutoPostBack="true" 
                        OnCheckedChanged="CheckBox1_CheckedChanged1"
                        />
                </ItemTemplate>
            </asp:TemplateField>

            </Columns>

            <FooterStyle BackColor="#990000" Font-Bold="True" ForeColor="White" />
        </asp:GridView>
        <asp:HiddenField ID="qtycheck" runat="server" ClientIDMode="Static" />

        <br />
        <asp:Button ID="Checkout_btn" runat="server"  Text="Proceed to Checkout"
            style="width:140px;height:60px;background-color:#FFCC99;border-radius:25px"
            OnClientClick="hasorder();return false;"/>
        <script>
            function hasorder() {
                var CheckQty = document.getElementById("qtycheck")
                if (CheckQty.value > 0) {
                    window.location.href = "/CheckOut.aspx"
                }
                else {
                    alert("Please select at least one Purchase before proceding to check out");
                    return false;
                }
            }
        </script>

现在这是一些标记,但仍然比您的第 2 页 table 少得多,您最好看看我们的第 2 页现在是非常少的标记!!

好的,所以我们有上面的。唯一真正的问题是,当您选中一个框时,我们需要对所有内容进行汇总。当您编辑或更改数量时,同样的事情 - 更新总数。

因此,我们每个部分的代码也非常有限。我会 post 一口气:

protected void Page_Load(object sender, System.EventArgs e)
{
    if (System.Web.UI.Page.IsPostBack == false)
    {
        // ok first page load, now check if reutrn from checkout 
        if (System.Web.UI.Page.Session["MyTable"] == null)
        {
            CreateData(); // first time here  - create the data
            System.Web.UI.Page.Session["MyTable"] = MyTable;    // save the data table
        }
        else
            // we have data - (so this is user change of mind from checkout page)
            MyTable = System.Web.UI.Page.Session["MyTable"];

        // ok, now load our data into the grid
        LoadData(); // load the data
    }
    else

        // this is a post back due to general changes and selections for this
        // page under normal and mutliple operations and choices by the user.

        // we dont' need to re-display the grid - it persists automatic
        // however the datatable variable does NOT persist - so get from session
        MyTable = System.Web.UI.Page.Session["MyTable"];
}

public void LoadData()
{
    MyTotal = 0;
    MyTotalQty = 0;
    qtycheck.Value = 0;
    GridView1.DataSource = MyTable;
    GridView1.DataBind();
}

protected void GridView1_RowDataBound(object sender, GridViewRowEventArgs e)
{
    if (e.Row.RowType == DataControlRowType.DataRow)
    {
        TextBox MyAmount = e.Row.FindControl("Amount");
        DataRow MyRow = MyTable.Rows(e.Row.RowIndex);

        MyRow("Amount") = MyRow("Qty") * MyRow("Price");

        if (MyRow("Purchased") == true)
        {
            // total up the qty purcchased and the amount
            MyTotal += MyRow("Amount");
            MyTotalQty += MyRow("Qty");
        }
    }
    else if (e.Row.RowType == DataControlRowType.Footer)
    {
        // this is our bottom last footer. 
        e.Row.Cells(3).Text = Strings.FormatCurrency(MyTotal);
        e.Row.Cells(2).Text = MyTotalQty;
        e.Row.Cells(1).Text = "Totals:";

        qtycheck.Value = MyTotalQty;     // a hidden control - to check for qty > 0 on checkout
    }
}

protected void CheckBox1_CheckedChanged1(object sender, EventArgs e)
{

    // user click on purchase a row - udpate totals.
    CheckBox cBox = sender;
    int RowID = cBox.Attributes("MyRow");
    MyTable.Rows(RowID).Item("Purchased") = cBox.Checked;

    // data table has been changed - so we call the load data routine to udpate 
    // our grid
    LoadData();
}

protected void Qty_TextChanged(object sender, EventArgs e)
{

    // user changed the qry in a row
    TextBox tBox = sender;
    int RowID = tBox.Attributes("MyRow");
    MyTable.Rows(RowID).Item("Qty") = tBox.Text;

    // data table has been changed - so we call the load data routine to udpate 
    // our grid
    LoadData();
}
}

现在这是一小段代码,但同样不是很多。

所以,你现在在 运行:

之后得到这个

所以,请注意当您选中一个框时我们做了什么!

我们简单地这样做:

protected void CheckBox1_CheckedChanged1(object sender, EventArgs e)
{

    // user click on purchase a row - udpate totals.
    CheckBox cBox = sender;
    int RowID = cBox.Attributes("MyRow");
    MyTable.Rows(RowID).Item("Purchased") = cBox.Checked;

    // data table has been changed - so we call the load data routine to udpate 
    // our grid
    LoadData();
}

所以,现在 NO MATCHING 问题确实存在,是吗?您单击一行,我们只需更改 Purchased 设置(true/false 标志)。就是这样 - 完成了!无需匹配。当您选中一个框时,我们会更改 table 值,然后简单地对代码说 will you please re-display the data!!!所以现在我们正在保存所有匹配的工作!!!

现在,结帐代码变成了在公园散步。

当您点击结帐按钮时,我们会跳转到结帐页面。

标记现在非常简单 - 因为它与第一页非常相似 - 但无法更改内容。因此:

<asp:GridView ID="GridView2" runat="server" ShowFooter="true"
            Font-Bold="True" Font-Size="Larger" BackColor="#FFCC99" 
             AutoGenerateColumns="False" 
         >

     <Columns>
       <asp:BoundField DataField="Product" HeaderText="Product" Headerstyle-width="250px" />
       <asp:BoundField DataField="Price" DataFormatString="{0:C2}" HeaderText="Price" Headerstyle-width="80px" />
       <asp:BoundField DataField="Qty"  HeaderText="Qty" Headerstyle-width="80px" />
       <asp:BoundField DataField="Amount"  HeaderText="Amount" Headerstyle-width="80px" />
     </Columns>
   <FooterStyle BackColor="#990000" Font-Bold="True" ForeColor="White" />

  </asp:GridView>

        <br />
        <asp:Button ID="ChangeOrder_btn" runat="server" PostBackUrl="~/SimpleButton.aspx" Text="Change order"
           style="width:140px;height:60px;background-color:#FFCC99;border-radius:25px"
              />
        <br />
    </div>

页面看起来像:

所以,您现在明白了我们为什么使用 table - 因为相同的数据现在驱动两个页面,我们的问题变得越来越小 - 而不是越来越大!!

我们的结帐页面代码是这样的:

class CheckOut : System.Web.UI.Page
{
private decimal MyTotal = 0;
private int MyTotalQty = 0;

protected void Page_Load(object sender, System.EventArgs e)
{
    DataTable MyTable = System.Web.UI.Page.Session["MyTable"];
    DataView dv = new DataView(MyTable); // we use data view in palce of data table - it can fitler!!

    dv.RowFilter = "Purchased = True";

    GridView2.DataSource = dv;
    GridView2.DataBind();
}

protected void GridView2_RowDataBound(object sender, GridViewRowEventArgs e)
{
    if (e.Row.RowType == DataControlRowType.DataRow)
    {
        MyTotal += e.Row.Cells(3).Text;
        MyTotalQty += e.Row.Cells(2).Text;
    }
    else if (e.Row.RowType == DataControlRowType.Footer)
    {
        e.Row.Cells(3).Text = Strings.FormatCurrency(MyTotal);
        e.Row.Cells(2).Text = MyTotalQty;
        e.Row.Cells(1).Text = "Totals:";
    }
}
}

因此,通过在第一页构建更好的设计和鼠标陷阱,以及更好的方法,下一页变得非常简单,因为我们 re-use 数据,re-use table 实际上也接近 re-used 网格!!!

要显示订单,我们只需获取 table,并按购买过滤结果。

还有返回并改变主意的按钮?好吧,它只是跳回到那个订单页面。

因此,虽然我们确实必须在第一页中建立更多的“标记”,但我们在第二页中大量减少了标记。