Search code examples
c#asp.netasp.net-corevisual-studio-2022

MasterPage Problem (Control 'ContentPlaceHolder1_btnMains' of type 'Button' must be placed inside a form tag with runat=server.)


So after i convert from normal webform into master page this happens, is says in the title, but masterpage cant add more form because it needs only 1 form, i actually didnt know why,

this is Menu.aspx

<%@ Page Title="Elfi's Western Food Menu" Language="C#" MasterPageFile="~/Navi.Master" AutoEventWireup="true" CodeBehind="Menu.aspx.cs" Inherits="ElfiRestaurant.Menu" %>

<asp:Content ID="Content1" ContentPlaceHolderID="head" runat="server">
    <link href="Style/Styles.css" rel="stylesheet" asp-append-version="true" />
    <link href="https://cdn.jsdelivr.net/npm/[email protected]/dist/css/bootstrap.min.css" rel="stylesheet" integrity="sha384-QWTKZyjpPEjISv5WaRU9OFeRpok6YctnYmDr5pNlyT2bRjXh0JMhjY6hW+ALEwIH" crossorigin="anonymous" />
</asp:Content>

<asp:Content ID="Content2" ContentPlaceHolderID="ContentPlaceHolder1" runat="server">
    <div class="container">
        <h1 class="text-center">Elfi's Western | Food Menu</h1>
        <a href="SalesOrder.aspx">SalesOrder.aspx</a>
        <div class="row">
            <div class="col-md-8 rounded">
                <div class="text-center mb-4 pt-5 rounded">
                        <asp:Button ID="btnMains" runat="server" Text="Mains" CssClass="btn btn-primary m-1" OnClick="FilterMains_Click" />
                        <asp:Button ID="btnSides" runat="server" Text="Sides" CssClass="btn btn-secondary m-1" OnClick="FilterSides_Click" />
                        <asp:Button ID="btnDrinks" runat="server" Text="Drinks" CssClass="btn btn-success m-1" OnClick="FilterDrinks_Click" />
                </div>
                <div class="row" id="menuItemsContainer">
                    <asp:Repeater ID="rptMenuItems" runat="server">
                        <ItemTemplate>
                            <div class="col-md-4 mb-3 menu-item " data-category='<%# Eval("CatId") %>'>
                                <div class="card">
                                    <img src='<%# Eval("MenuImage") %>' class="card-img-top" alt='<%# Eval("MenuTitle") %>' />
                                    <div class="card-body">
                                        <h5 class="card-title"><%# Eval("MenuTitle") %></h5>
                                        <p class="card-text"><%# Eval("MenuDesc") %></p>
                                        <p class="card-text fw-semibold fs-4 pt-2 pb-2">RM<%# Eval("MenuPrice") %></p>
                                        <asp:Button ID="btnAddToCart" runat="server" Text="Add to Cart" CssClass="btn btn-primary"
                                            CommandArgument='<%# Eval("MenuId") %>' OnClick="AddToCart_Click" />
                                    </div>
                                </div>
                            </div>
                        </ItemTemplate>
                    </asp:Repeater>
                </div>
            </div>
            <%----CART SECTION----%>
            <div class="col-md-4 pt-5 p-2">
                <div class="cart-container shadow p-3 mb-5 bg-body-tertiary rounded border border-light-subtle">
                    <h4>Cart</h4>
                    <p id="cartDateTime">
                        <asp:Label ID="lblDateTime" runat="server" />
                    </p>
                    <asp:Repeater ID="rptCart" runat="server">
                        <HeaderTemplate>
                            <table class="table table-striped table-bordered cart-table">
                                <thead>
                                    <tr>
                                        <th>Id</th>
                                        <th>Title</th>
                                        <th>Price</th>
                                        <th>Quantity</th>
                                        <th>Sub Total</th>
                                    </tr>
                                </thead>
                                <tbody>
                        </HeaderTemplate>
                        <ItemTemplate>
                            <tr>
                                <td><%# Eval("MenuId") %></td>
                                <td><%# Eval("MenuTitle") %></td>
                                <td>RM<%# Eval("MenuPrice", "{0:0.00}") %></td>
                                <td><%# Eval("Quantity") %></td>
                                <td>RM<%# Eval("Subtotal", "{0:0.00}") %></td>
                            </tr>
                        </ItemTemplate>
                        <FooterTemplate>
                            </tbody>
                </table>
                        </FooterTemplate>
                    </asp:Repeater>
                    <div class="text-center">
                        <p>Total Amount: RM<asp:Label ID="lblTotalAmount" runat="server" Text="0.00" /></p>
                        <asp:Button ID="btnConfirmOrder" runat="server" Text="Order" CssClass="btn btn-success"
                            OnClick="btnConfirmOrder_Click" />
                        <asp:Button ID="btnCancelOrder" runat="server" Text="Cancel" CssClass="btn btn-danger" OnClick="btnCancelOrder_Click" />
                        <asp:Button ID="btnNewSales" runat="server" Text="Reset" CssClass="btn btn-secondary" OnClick="btnNewSales_Click" />
                    </div>
                    <hr />
                    <%----RECEIPT SECTION----%>
                    <div class="mt-5 border border-dark-subtle p-4 m-4 rounded-2">
                        <br />
                        <h4><b>Receipt</b></h4>
                        <hr />
                        <br />
                        <p><b>Total Amount</b>: RM<asp:Label ID="lblReceiptTotalAmount" runat="server" Text="0.00" CssClass="text-end" /></p>
                        <p><b>Service Tax (6%)</b>: RM<asp:Label ID="lblServiceTax" runat="server" Text="0.00" CssClass="text-end" /></p>
                        <p><b>Amount After Tax</b>: RM<asp:Label ID="lblAmountAfterTax" runat="server" Text="0.00" CssClass="text-end" /></p>
                        <p><b>Rounding</b>: RM<asp:Label ID="lblRounding" runat="server" Text="0.00" CssClass="text-end" /></p>
                        <p><b>Amount Rounded</b>: RM<asp:Label ID="lblAmountRounded" runat="server" Text="0.00" CssClass="fs-5 text-end" /></p>
                        <asp:Label ID="lblThankYouMessage" runat="server" Text="Thank you for your order!" Visible="false" CssClass="fs-4 fw-medium"></asp:Label>
                    </div>
                </div>
            </div>
        </div>
        <%--MODAL POPUP SECTION--%>
        <div class="modal fade" id="confirmModal" tabindex="-1" role="dialog" aria-labelledby="confirmModalLabel" aria-hidden="true">
            <div class="modal-dialog" role="document">
                <div class="modal-content">
                    <div class="modal-header">
                        <h4 class="modal-title" id="confirmModalLabel">Confirm Order?</h4>
                    </div>
                    <div class="modal-body">
                        Are you sure you want to proceed with this Order?
                    </div>
                    <div class="modal-footer">
                        <button type="button" class="btn btn-secondary" data-dismiss="modal">Cancel</button>
                        <asp:Button ID="btnProceedOrder" runat="server" Text="Order" CssClass="btn btn-success" OnClick="ProceedOrder_Click" />
                    </div>
                </div>
            </div>
        </div>
        <%--THANK YOU MODAL SECTION--%>
        <div class="modal fade" id="thankYouModal" tabindex="-1" role="dialog" aria-labelledby="thankYouModalLabel" aria-hidden="true">
            <div class="modal-dialog" role="document">
                <div class="modal-content">
                    <div class="modal-header">
                        <h4 class="modal-title" id="thankYouModalLabel">Order Confirmed</h4>
                        &nbsp;
            <svg xmlns="http://www.w3.org/2000/svg" width="24" height="24" viewBox="0 0 24 24" style="fill: rgba(0, 0, 0, 1)">
                <path d="M12 2C6.486 2 2 6.486 2 12s4.486 10 10 10 10-4.486 10-10S17.514 2 12 2zm-1.999 14.413-3.713-3.705L7.7 11.292l2.299 2.295 5.294-5.294 1.414 1.414-6.706 6.706z"></path></svg>
                    </div>
                    <div class="modal-body">
                        Thank you for your order!
                    </div>
                    <div class="modal-footer">
                        <button type="button" class="btn btn-secondary" data-dismiss="modal">Close</button>
                    </div>
                </div>
            </div>
        </div>
    </div>
    <script src="https://unpkg.com/[email protected]/dist/boxicons.js"></script>
    <script src="https://code.jquery.com/jquery-3.5.1.slim.min.js"></script>
    <script src="https://cdn.jsdelivr.net/npm/@popperjs/[email protected]/dist/umd/popper.min.js"></script>
    <script src="https://stackpath.bootstrapcdn.com/bootstrap/4.5.2/js/bootstrap.min.js"></script>
</asp:Content>

<%--<%@ Page Language="C#" AutoEventWireup="true" CodeBehind="Menu.aspx.cs" Inherits="ElfiRestaurant.Menu" %>

<!DOCTYPE html>
<html xmlns="http://www.w3.org/1999/xhtml">
<head runat="server">

</head>
<body>
    <form id="form1" runat="server">
        
    </form>
</body>
</html>--%>

this is menu.aspx.cs

using System;
using System.Collections.Generic;
using System.Configuration;
using System.Data;
using System.Data.SqlClient;
using System.Data.SqlTypes;
using System.Web.UI;
using System.Web.UI.WebControls;

namespace ElfiRestaurant
{
    public partial class Menu : System.Web.UI.Page
    {
        private List<CartItem> Cart
        {
            get
            {
                if (Session["Cart"] == null)
                {
                    Session["Cart"] = new List<CartItem>();
                }
                return (List<CartItem>)Session["Cart"];
            }
            set
            {
                Session["Cart"] = value;
            }
        }

        protected void Page_Load(object sender, EventArgs e)
        {
            if (!IsPostBack)
            {
                lblDateTime.Text = DateTime.Now.ToString("dd MMMM yyyy, HH:mm:ss");
                BindMenuItems("1"); // mains default 
                BindCart();
            }
        }

        protected void FilterMains_Click(object sender, EventArgs e)
        {
            BindMenuItems("1"); // show Mains
        }

        protected void FilterSides_Click(object sender, EventArgs e)
        {
            BindMenuItems("2"); // show Sides
        }

        protected void FilterDrinks_Click(object sender, EventArgs e)
        {
            BindMenuItems("3"); // show Drinks
        }

        private void BindMenuItems(string category)
        {
            string connString = ConfigurationManager.ConnectionStrings["RestaurantDB"].ConnectionString;
            using (SqlConnection conn = new SqlConnection(connString))
            {
                string query = "SELECT MenuId, CatId, MenuTitle, MenuPrice, MenuDesc, MenuImage FROM Menu WHERE CatId = @CatId";
                SqlDataAdapter da = new SqlDataAdapter(query, conn);
                da.SelectCommand.Parameters.AddWithValue("@CatId", category);
                DataTable dt = new DataTable();
                da.Fill(dt);

                rptMenuItems.DataSource = dt;
                rptMenuItems.DataBind();
            }
        }

        protected void AddToCart_Click(object sender, EventArgs e)
        {
            Button btn = (Button)sender;
            int menuId = int.Parse(btn.CommandArgument);
            string connString = ConfigurationManager.ConnectionStrings["RestaurantDb"].ConnectionString;
            using (SqlConnection conn = new SqlConnection(connString))
            {
                string query = "SELECT MenuId, MenuTitle, MenuPrice FROM Menu WHERE MenuId = @MenuId";
                SqlCommand cmd = new SqlCommand(query, conn);
                cmd.Parameters.AddWithValue("@MenuId", menuId);
                conn.Open();
                SqlDataReader reader = cmd.ExecuteReader();
                if (reader.Read())
                {
                    int id = reader.GetInt32(0);
                    string title = reader.GetString(1);
                    float price = (float)reader.GetDouble(2);
                    AddToCart(id, title, price);
                    // Close the DataReader before executing another command
                    reader.Close();
                    // Check if a SalesId exists in the session
                    string salesId;
                    if (Session["SalesId"] != null)
                    {
                        salesId = Session["SalesId"].ToString();
                    }
                    else
                    {
                        // Generate a new SalesId
                        salesId = Guid.NewGuid().ToString("N");
                        // Store the SalesId in the session
                        Session["SalesId"] = salesId;
                    }
                    // Call the stored procedure to add the item to the SalesOrder table
                    using (SqlCommand cmdAddToSalesOrder = new SqlCommand("AddItemToSalesOrder", conn))
                    {
                        cmdAddToSalesOrder.CommandType = CommandType.StoredProcedure;
                        cmdAddToSalesOrder.Parameters.AddWithValue("@SalesId", salesId);
                        cmdAddToSalesOrder.Parameters.AddWithValue("@MenuId", id);
                        cmdAddToSalesOrder.Parameters.AddWithValue("@Quantity", 1); // Assuming quantity is 1
                        cmdAddToSalesOrder.Parameters.AddWithValue("@SalesDate", DateTime.Now);
                        cmdAddToSalesOrder.ExecuteNonQuery();
                    }
                }
            }
        }




        private void AddToCart(int menuId, string title, float price)
        {
            List<CartItem> cart = Cart;
            var item = cart.Find(i => i.MenuId == menuId);
            if (item != null)
            {
                item.Quantity++;
                item.Subtotal = item.Quantity * item.MenuPrice;
            }
            else
            {
                cart.Add(new CartItem
                {
                    MenuId = menuId,
                    MenuTitle = title,
                    MenuPrice = price,
                    Quantity = 1,
                    Subtotal = price
                });
            }
            Cart = cart;
            BindCart();
        }

        private void BindCart()
        {
            rptCart.DataSource = Cart;
            rptCart.DataBind();
            float totalAmount = 0;
            foreach (var item in Cart)
            {
                totalAmount += item.Subtotal;
            }
            lblTotalAmount.Text = totalAmount.ToString("0.00");
            CalculateReceipt(totalAmount);
        }

        protected void btnConfirmOrder_Click(object sender, EventArgs e)
        {
            if (IsCartEmpty())
            {
                ScriptManager.RegisterStartupScript(this, GetType(), "showalert", "alert('Please add your items before confirming.');", true);
            }
            else
            {
                ScriptManager.RegisterStartupScript(this, GetType(), "showModal", "$('#confirmModal').modal('show');", true);
            }
        }

        protected void ProceedOrder_Click(object sender, EventArgs e)
        {
            ConfirmOrder();
            DisplayThankYouMessage();
            DisplayThankYouModal();
        }


        protected void btnCancelOrder_Click(object sender, EventArgs e)
        {
            CancelOrder();
            HideThankYouMessage();
        }

        protected void btnNewSales_Click(object sender, EventArgs e)
        {
            NewSales();
            HideThankYouMessage();
        }

        private void ConfirmOrder()
        {
            string connString = ConfigurationManager.ConnectionStrings["RestaurantDb"].ConnectionString;
            string salesId = Session["SalesId"] != null ? Session["SalesId"].ToString() : string.Empty;

            if (!string.IsNullOrEmpty(salesId))
            {
                using (SqlConnection conn = new SqlConnection(connString))
                {
                    conn.Open();
                    using (SqlCommand cmd = new SqlCommand("ConfirmOrder", conn))
                    {
                        cmd.CommandType = CommandType.StoredProcedure;
                        cmd.Parameters.AddWithValue("@SalesId", salesId);
                        cmd.ExecuteNonQuery();
                    }
                }
                Cart.Clear(); // Clear the cart after confirming order
                BindCart(); // Refresh the cart display
            }
        }


        private void CancelOrder()
        {
            string connString = ConfigurationManager.ConnectionStrings["RestaurantDb"].ConnectionString;
            using (SqlConnection conn = new SqlConnection(connString))
            {
                conn.Open();
                foreach (var item in Cart)
                {
                    string query = "EXEC CancelOrder @SalesId";
                    SqlCommand cmd = new SqlCommand(query, conn);
                    cmd.Parameters.AddWithValue("@SalesId", Guid.NewGuid().ToString("N"));
                    cmd.ExecuteNonQuery();
                }
            }
            Cart.Clear(); // Clear the cart after canceling order
            BindCart(); // Refresh the cart display
        }

        protected bool IsCartEmpty()
        {
            return Cart.Count == 0;
        }


        private void NewSales()
        {
            Cart.Clear(); // Clear the cart for new sales
            BindCart(); // Refresh the cart display
        }

        private void DisplayThankYouMessage()
        {
            lblThankYouMessage.Visible = true;
        }

        private void DisplayThankYouModal()
        {
            ScriptManager.RegisterStartupScript(this, GetType(), "showThankYouModal", "$('#thankYouModal').modal('show');", true);
        }

        private void HideThankYouMessage()
        {
            lblThankYouMessage.Visible = false;
        }

        private void CalculateReceipt(float totalAmount)
        {
            float serviceTax = totalAmount * 0.06f;
            float amountAfterTax = totalAmount + serviceTax;
            float rounding = (float)Math.Round(amountAfterTax) - amountAfterTax;
            float amountRounded = (float)Math.Round(amountAfterTax);

            lblReceiptTotalAmount.Text = totalAmount.ToString("0.00");
            lblServiceTax.Text = serviceTax.ToString("0.00");
            lblAmountAfterTax.Text = amountAfterTax.ToString("0.00");
            lblRounding.Text = rounding.ToString("0.00");
            lblAmountRounded.Text = amountRounded.ToString("0.00");
        }
    }

    public class CartItem
    {
        public int MenuId { get; set; }
        public string MenuTitle { get; set; }
        public float MenuPrice { get; set; }
        public int Quantity { get; set; }
        public float Subtotal { get; set; }
    }
}

What did i try is adding form on the button but error says cant be more than 1 form


Solution

  • When you create a new webform, then select the master page. If you had an existing .aspx page without a master page, then I strong suggest you re-create the page, and of course select new form with master page.

    Hence, this:

    enter image description here

    Then this:

    enter image description here

    The reason I suggest the above is in most cases less work is required to re-create the page.

    So, let Visual Studio create this new page, and that ensures the page is correctly created and wired up correctly.

    You can try converting an existing page by hand, but you often make mistakes, so create a new page.

    The HTML standard is to only allow and have one form tag per page. The master page will "already" have the form tag, so in your new child page, you can NOT have a form tag anymore, and you have to remove them during this conversion process. You not have a "head" tag, and you also not have a "body" tag.

    So, after you create a new aspx page (having selected new page with master), then you have this markup:

    <%@ Page Title="" Language="C#" MasterPageFile="~/Site.Master" 
        AutoEventWireup="true" 
        CodeBehind="WebForm1.aspx.cs" 
        Inherits="CSharpWebApp1.Test3.WebForm1" %>
    
    <asp:Content ID="Content1" ContentPlaceHolderID="MainContent" runat="server">
    
    
    </asp:Content>
    

    You can now open up the older page, and cut + paste everything starting from the form tag, but not including the form tag.

    You also of course have to copy the code behind.

    So, any web page with a master page will not, does not, and can not have any form tags in that page (so remove them).

    In some cases, the master page may have more then one section, and thus multiple sections will appear in the child page, such as say this for a newly created page.

    <asp:Content ID="Content1" ContentPlaceHolderID="head" runat="server">
    
    </asp:Content>
    
    <asp:Content ID="Content2" ContentPlaceHolderID="MainContent" runat="server">
    
    </asp:Content>
    

    Since I don't need (nor care for a heading part of the page), then I'll often delete the head content section.

    Now, with above, inside of the content areas (ContentPlaceHolder), then you can paste in your original page markup. As noted, copy only what is inside of the form tag, but not including the form tag.

    So, these so-called child pages don't have a form tag like a regular .aspx page (one created without a master page).

    In your example, you can see that you have this markup:

    </head>
    <body>
        <form id="form1" runat="server">
        
        </form>
    </body>
    

    So, in these child pages, you don't have a "body", and you don't have a "head" section. This is why I am suggesting to re-create the page, so you start out with a correctly created and formatted child page.

    So, only copy what was between the form tag in the older page.

    You will of course have to transfer the code behind from that previous page, and once again, use caution, and don't copy/paste in the code behind forms class name, but only the code stubs inside of that class.

    Follow the above to convert an existing page to work with a master page. As noted, you could try and modify the older page, but there are far too many pitfalls and small issues to get 100% correct for such a page to work.