简体   繁体   English

如何强制用户至少单击 C# 中复选框的 6 个选项中的 2 个?

[英]How to force user to at least click on 2 out of 6 choices on a check box in c#?

namespace PizzaApp
{
    public partial class PizzaOrder : Form
    {
        // Initializing the toppings to its cost
        // Double type since it could have decimal points
        public double Small = 5.50;
        public double Medium = 11.75;
        public double Large = 15.00;
        public double Pepperoni = 0.75;
        public double Onion = 0.75;
        public double Mushroom = 0.75;
        public double BlackOlives = 0.75;
        public double Pineapple = 0.75;
        public double ExtraCheese = 0.75;

        public static double Cost = 0.00; // Keeps track of total cost
        

        public PizzaOrder()
        {
            InitializeComponent();
        }

        private void orderButton_Click(object sender, EventArgs e)
        {
           
            // If small size pizza radio button is checked, I do cost - 1.50 because 2 ingredients are free
            if (smallRadioButton.Checked == true)
            {
                Cost += Small;
                Cost -= 1.50;
            }
            // If medium size pizza radio button is checked, I do cost - 2.25 because 3 ingredients are free
            if (mediumRadioButton.Checked == true)
            {
                Cost += Medium;
                Cost -= 2.25;
            }
            // If large size pizza radio button is checked, I do cost - 3.00 because 4 ingredients are free
            if (largeRadioButton.Checked == true)
            {
                Cost += Large;
                Cost -= 3.00;
            }


            //Ingredrients if statements
            if (pepperoniCheckBox.Checked == true)
            {
                Cost += Pepperoni;

            }
            if (onionCheckBox.Checked == true)
            {
                Cost += Onion;

            }
            if (mushroomCheckBox.Checked == true)
            {
                Cost += Mushroom;

            }
            if (blackOlivesCheckBox.Checked == true)
            {
                Cost += BlackOlives;

            }
            if (pineappleCheckBox.Checked == true)
            {
                Cost += Pineapple;

            }
            if (extraCheeseCheckBox.Checked == true)
            {
                Cost += ExtraCheese;

            }

           
        }

        private void sizeGroupBox_Enter(object sender, EventArgs e)
        {

        }

        private void ingredientsGroupBox_Enter(object sender, EventArgs e)
        {

        }

        private void PizzaOrder_Load(object sender, EventArgs e)
        {

        }

        private void priceLabel_Click(object sender, EventArgs e)
        {
          
        }

        private void totalPriceTextBox_TextChanged(object sender, EventArgs e)
        {
            totalPriceTextBox.Text = Cost.ToString();
        }
    }
}

When the user takes small pizza for example 2 out of 6 ingredients are free(Medium is 3 and large is 4 free ingredients).例如,当用户拿小披萨时,6 种成分中有 2 种是免费的(中型是 3 种,大的是 4 种免费成分)。 I couldn't find any other way to implement this so I just subtracted the free ingredients from the pizza size.我找不到任何其他方法来实现这一点,所以我只是从比萨大小中减去了免费成分。 I'm now stuck on how to force the user to choose at least those free ingredients so the pizza wont cost less than the initial price.我现在被困在如何强迫用户至少选择那些免费成分,以便比萨饼的成本不会低于初始价格。

This is a common flaw in beginners code, that there is basically zero abstraction/seperation between UI and data / business logic.这是初学者代码中的一个常见缺陷,即 UI 和数据/业务逻辑之间基本上是零抽象/分离。 Consider using a proper OOP approach, then things quickly start to seem much clearer.考虑使用适当的 OOP 方法,然后事情很快就会变得更加清晰。

Example:例子:

public enum PizzaSize
{
    Small,
    Medium,
    Large
}

public class PizzaTopping
{
    public string Name { get; set; }
    public decimal Price { get; set; }
}

public class PizzaOrder
{
    private static readonly Dictionary<PizzeSize, decimal> pizzaPrices = new Dictionary<PizzeSize, decimal>
    {
         { PizzaSize.Small, 5.5m },
         { PizzaSize.Medium, 11.75m },
         { PizzaSize.Large, 15m },
    };
    
    private static readonly Dictionary<PizzeSize, decimal> freeToppingsCounts = new Dictionary<PizzeSize, decimal>
    {
         { PizzaSize.Small, 2 },
         { PizzaSize.Medium, 3 },
         { PizzaSize.Large, 4 },
    };
    
    public PizzaSize Size { get; set; }
    public List<PizzaTopping> Toppings { get; set; } = new List<PizzaTopping>();
    
    public decimal GetTotalPrice()
    {
        var totalPrice = pizzaPrices[this.Size];
        var freeToppings = freeToppingsCounts[this.Size];
        var counter = 0;
        foreach (var topping in this.Toppings.OrderBy(x => x.Price))
        {
            counter++;
            if (counter > freeToppings)
            {
                totalPrice += topping.Price;
            }
        }
        return totalPrice;
    }
}


public class PizzaOrderForm : Form
{
    var order = GetPizzaOrder(); // create your order from the UI here
    var totalPrice = order.GetTotalPrice();
}

(Disclaimer: I quickly hacked this together in Notepad, it's not meant to be perfect, just to make my point.) (免责声明:我很快在记事本中将其破解,这并不意味着完美,只是为了表明我的观点。)

I would start off by defining a class which holds a reference to the relevant checkbox and the price for that topping我将首先定义一个类,该类包含对相关复选框的引用以及该浇头的价格

public class Topping
{
    public CheckBox Selector {get;}
    public double Cost {get;}

    public Topping(CheckBox selector, double cost)
    {
       this.Selector = selector;
       this.Cost = cost;
    }
}

And then define an array of Topping in your form instead of a bunch of discrete variables for each one:然后在您的表单中定义一个Topping数组,而不是为每个变量定义一堆离散变量:

public partial class PizzaOrder : Form
{
   private Topping[] toppings = new Topping[]{
        new Topping(pepperoniCheckBox, 0.75),
        new Topping(onionCheckBox, 0.75),
        new Topping(mushroomCheckBox, 0.75),
        new Topping(blackOlivesCheckBox, 0.75),
        // .. etc
   };

This is useful, as you can now determine the number of selected toppings (all those which are checked)这很有用,因为您现在可以确定所选浇头的数量(所有选中的浇头)

var numToppingsSelected = toppings.Where(x => x.Selector.Checked).Count();

You can also get an IEnumerable<Topping> of the selected ones - perhaps order them by Cost and skip the cheapest 2, before getting the total cost of the remaining selection.您还可以获取所选选项的IEnumerable<Topping> - 可能按Cost排序并跳过最便宜的 2,然后再获取剩余选项的总成本。

var selectedToppings = toppings.Where(x => x.Selector.Checked).OrderBy(x => x.Cost);
var selectedToppingsExceptFirst2 = selectedToppings.Skip(2);
var costOfRemainingToppings = selectedToppingsExceptFirst2.Sum(x => x.Cost);

Hopefully this gets you well on your way to building a more sensible order button handler.希望这能让您在构建更合理的订单按钮处理程序的道路上走得更远。 Let me know if you have any follow up questions on how to do so.如果您对如何执行此操作有任何后续问题,请告诉我。

Is part of your requirements that a user cannot have a pizza with one topping, even if they don't want any of the other five?您的部分要求是用户不能吃有一种配料的比萨饼,即使他们不想要其他五种配料中的任何一种吗? Because if not, then you're introducing a constraint that is not supposed to be there, making this an XY problem.因为如果没有,那么您将引入一个不应该存在的约束,从而使其成为 XY 问题。

I'm going to assume that this constraint should not be there.我将假设这个约束不应该存在。 Note also that I'm trying to make minimal changes to your code, as opposed to redesigning this with more bells and whistles, because I surmise this is a beginner's task.另请注意,我试图对您的代码进行最小的更改,而不是用更多的花里胡哨重新设计它,因为我认为这是初学者的任务。
I would've tackled this differently from the beginning, but that would be a more advanced approach and it would require rewriting your entire solution from scratch, which is somewhat off-topic here and not a good lesson for you either.我会从一开始就以不同的方式解决这个问题,但这将是一种更高级的方法,它需要从头开始重写整个解决方案,这在这里有点偏离主题,对您来说也不是一个好教训。

The problem here is that your task requires considering a group of toppings ("the first two [of the list of chosen toppings] are free"), but your code only considers each topping checkbox individually.这里的问题是您的任务需要考虑一组浇头(“ [所选浇头列表中前两个]是免费的”),但您的代码仅单独考虑每个浇头复选框。 As it stands, your code is not considering the collection of toppings as a group.就目前而言,您的代码并未将浇头集合视为一个组。

I've noticed that all toppings cost the same.我注意到所有浇头的价格都一样。 Is this a given?这是给定的吗? Or is it possible that toppings can have different prices?或者浇头有可能有不同的价格吗?

If all toppings always cost the same , the math is very easy.如果所有配料的价格始终相同,则数学计算非常简单。 The total price for the toppings is:浇头的总价为:

([amount_of_toppings] - 2) * [price_of_a_topping]

When amount_of_toppings is less than or equal to 2, you don't even have to calculate it.amount_of_toppings小于或等于 2 时,您甚至不必计算它。

How do you know the amount of toppings?你怎么知道浇头的数量? Well, you count the checked boxes.好吧,您数一下选中的框。

public double GetToppingsTotalPrice()
{
    int counter = 0;

    if(pepperoniCheckBox.Checked) 
        counter++;

    if(onionCheckBox.Checked) 
        counter++;

    // and so on

    if(counter > 2)
        return (counter-2) * this.toppingPrice;
    else
        return 0; 
}

If toppings can have different prices , then you need more information.如果浇头可以有不同的价格,那么您需要更多信息。 How do you decide which toppings are free?你如何决定哪些浇头是免费的? You could presume that the cheapest ones will be free, but this is something that should be confirmed in the description.您可以假设最便宜的将是免费的,但这应该在描述中确认。

Let's run with the idea that the cheapest two will be free.让我们相信最便宜的两个将是免费的。 This means we need to first find out which toppings were selected, what their individual price is, remove the two lowest prices, and then add the remaining prices.这意味着我们需要首先找出选择了哪些浇头,它们各自的价格是多少,去掉两个最低的价格,然后将剩余的价格相加。

When doing these kinds of operations on a collection, LINQ is a clean and easy way to do so, so I'm going to use it in this solution.在集合上执行这些类型的操作时,LINQ 是一种干净且简单的方法,因此我将在此解决方案中使用它。

public double GetToppingsTotalPrice()
{
    List<double> addedToppingPrices = new List<double>();

    if(pepperoniCheckBox.Checked) 
        addedToppingPrices.Add(this.Pepperoni);

    if(onionCheckBox.Checked) 
        addedToppingPrices.Add(this.Onion);

    // and so on

    // Stop here if there aren't any paid toppings.
    if(addedToppingPrices.Count() <= 2)
        return 0;

    return addedToppingPrices
             .OrderBy(x => x)  // Sort from cheapest to most expensive
             .Skip(2)          // Skip the first two
             .Sum(x => x);     // Sum the remaining numbers
}

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM