I'm very new to coding and am currently learning C#. More specifically I'm currently struggling with using checkboxes in group boxes. What I'm wondering is if it's possible to have multiple checkboxes in the same 'if' statement?
What I mean by is that, instead of just (for example):
private void button1_Click(object sender, Eventargs e)
{
float optionACheckBox = 149.00f;
if (checkBox1.Checkstate == CheckState.Checked)
{
finalPrice = (optionACheckBox + 60)
}
MessageBox.Show(finalPrice);
}
how would I make it so that instead it would be something like:
if (checkBox1 & checkBox2 = CheckState.Checked)
{
((Value of checkBox1) + (Value of checkBox2) + 60)
}
where if the user checks checkBox1 & checkBox2 then both values can be used in the equation?
Regarding this, would it also be possible to make code that checks if any/what combination of the CheckBoxes in the GroupBox have been checked? Rather than me writing an 'if' statement for every single combination of the different CheckBoxes?
Thank you to anyone who takes the time to read this and for any tips given
More Context (Sorry this is my second ever StackOverFlow post so I'm not very good at proper formatting):
Using Visual Studio 2019
There are three CheckBoxes in total, and all three are in one GroupBox
The CheckBoxes and GroupBox were added to the form using the toolbox feature
You didn't really tell us much about your logic but it seems like you want a hypothetical scenario like:
some fixed base price of the pizza
a price for each topping
a fixed price for applying any number of toppings
As such I'd look at accumulation:
float price = 100;
if(anchoviesCheckbox.Checked)
basePrice += 20;
if(olivesCheckbox.Checked)
basePrice += 30;
if(chilliesCheckbox.Checked)
basePrice += 40;
//if anchovies AND chillies are chosen there is a surcharge because the most of the chefs are allergic to this combination and we have to get the manager to do it
if(anchoviesCheckbox.Checked && chilliesCheckBox.Checked)
basePrice += 50;
//if any one OR more topping has been applied, there is a surcharge
if(anchoviesCheckbox.Checked || olivesCheckbox.Checked || chilliesCheckbox.Checked)
basePrice += 60;
These accumulate because there is no else - if the checkbox is checked, cost is added to the final price. Each checkbox is viewed in isolation. Later some also act in combination.
Note you could of course also check if the base price is greater than 100 to know if to apply a surcharge..
Once you've got that clear in your mind how it works, you can save yourself some of those ifs by treating the checkboxes in the group box as a collection
You can do this in the form constructor:
//put the prices in the checkbox Tag:
anchoviesCheckbox.Tag = 20;
olivesCheckbox.Tag = 30;
chilliesCheckbox.Tag = 20;
Then in your price calc method you can do something like:
float basePrice = 100:
foreach(var cb in toppingsGroupBox.Controls.OfType<CheckBox>().Where(cb => cb.Checked))
basePrice += (int)cb.Tag;
This uses LINQ to pull out just the checked checkboxes, and then extract the price from their tag and add it on. You could even do:
float basePrice = 100 +
toppingsGroupBox.Controls
.OfType<CheckBox>()
.Where(cb => cb.Checked)
.Sum(cb => (int)cb.Tag);
For your adding a surcharge if any topping is chosen:
if(toppingsGroupBox.Controls
.OfType<CheckBox>()
.Any(cb => cb.Checked)))
basePrice += 60;
You could now add 100 different toppings checkboxes to the form and so long as you put the price in the tag there is no more code needs adding to the method that calculates the price
The "manager must add anchovies and chillies" surcharge could also be done with LINQ. For that you'd have to define a custom set of checkboxes and if they are all ticked then apply the surcharge:
class PizzaForm:Form{
CheckBox[] managerSurcharge;
PizzaForm() { // constructor
...
managerSurcharge = new[]{ anchoviesCheckBox, chilliesCheckBox };
}
Then in the price:
if(managerSurcharge.All(cb => cb.Checked))
basePrice += 50;
Not an if in sight! 😀 (yeah, it's really hard to do away with every if..)
But do name your controls and variables well; this code here is easily readable and obvious what it does because of the names. That manager surcharge scenario would be a lot more confusing if you write:
CheckBox array1 = new[]{ checkbox12, checkbox7 }
You can use switch case judgments to assign different outcomes to these different choices.
But because every combination is a judgment situation, no matter what judgment method you use, you need to judge them separately.
The judgment to judge that both are selected should be as follows:
if (checkBox1.Checked && checkBox2.Checked)
{
//To do something
}
Some documents:
checked 、&&、||、== and !=
First of all, you can't compare the checkbox itself with a CheckState so you have to use checkBox1.CheckState == CheckState.Checked or better using Boolean "Checked" property: if(checkBox1.Checked) which will check if the checkbox is checked.
As for your last Question on how to detect if any checkbox is checked you can use || the logical "OR" Operator:
if(checkBox1.Checked || checkBox2.Checked || checkBox3.Checked)
Update
Logical Operator vs Conditional Short Circuit Operator
Logical Operator: & is used to ensure all Operands are evaluated and checked.
Conditional Short Circuit Operator: && is used to skip the right side Operand.
As mentioned in the comments, both will work in the vast majority of the cases, but I would always use the "Conditional Short Circuit Operators" when possible, to skip the unnecessary Check of the right side Operand.
Related
I have a table in my database that has columns 'price', 'percentage' and 'ID'.
Percentage column needs to be calculated using colum 'price' and 'id'. There is an initial price, followed by three increased prices, all of them having the same ID. I need to find a method that calculates the percentage column in my database using C#.
I attach a picture for better understanding how it should be.
I am writing an import system using Linq and I have already imported all the columns, but now I need to calculate percentage for the increasing prices and I am really struggeling with this. Maybe someone have some god suggestions of how I can solve this.
UPDATE:
public static void calculateProcentage(string id, double price, double, double percentage)
{
var percentageQuery = from l in db.Table
where l.ID == id
&& l.Price == price && l.Percentage != percentage
select l;
foreach (Table l in percentageQuery)
{
//double newPercentage = (double) l.Percentage;
//DataTable table = new DataTable();
// int rowCount = table.Rows.Count;
DataGridView dataGridView = new DataGridView();
for (int i = 0; i < dataGridView.Rows.Count; i++)
{
if (l.Building_vigor_ID == building_vigor_id)
{
//var priceRows = db.V_Leases.Select(x => x.Price_sqm).ToList();
// get a list of the rows of the price column
// get a list of the rows of the price column
var priceRows = (from r in db.Table
select r.Price).ToList();
percentage = (double)(priceRows[i] / priceRows[i + 1]);
}
}
}
try
{
db.SubmitChanges();
Console.Write("Percentage updated");
//Console.ReadKey();
}
catch (Exception e)
{
Console.WriteLine(e);
Console.Write("Could not update percentage");
//Console.ReadKey();
}
}
That is what I have tried. I bassicaly wanted to make it like an update method with only updating column percentage. But did not actualy work. I am pretty new with Linq sow it may be some bad code written here.
The disclaimer
I am pretty new with Linq sow it may be some bad code written here.
Your question, and the way you've attempted to solve this, are fraught with inconsistencies and seemingly contradictory expectations.
As it stands, the question you've asked is not answerable due to lack of information. However, I do think I understand what the actual problem is that you're trying to solve, so I'll give you that answer. But first, let me explain how I've interpreted your question.
My assumptions about your actual question
As I understand it, you're trying to calculate the percentage based on the previous value.
A more generalized example:
PRICE % ID
------------------------
100 A 1
103 B 1
100 C 2
150 D 2
A and C should both be 0 as they are the "base" price of their respective ID value.
B should be 3% because its price is 103% of A's price.
D should be 50% because its price is 150% of C's price.
My below answer will assume that this is correct.
There is also a problem with your expected values. In your example, you have listed the percentage of 19.79 (compared to 19.21) as 0.3.
This does not make sense. The difference is 3%. There are two different (acceptable) ways to denote this in the percentage column:
3, because it is expressed as a percentage (3%)
0.03, because it is expressed as a decimal value (3% = 0.03)
Your usage of 0.3 makes no sense, as I would interpret this as either 0.3% (option 1) or 30% (option 2).
In order to maintain consistency, my answer will assume that you want the decimal value (0.03 in the above example)
I assume your data class is constructed as follows:
public class Foo
{
public decimal Price { get; set; }
public decimal Percentage { get; set; }
public int ID { get; set; }
}
I don't quite understand how you're using the method. You supply three parameters (string id, double price, double, double percentage), but then you go on to select your data as follows:
var percentageQuery = from l in db.Table
where l.ID == id
&& l.Price == price && l.Percentage != percentage
select l;
It makes little sense to supply a percentage, and then pick everything that's different from that percentage. You have no idea of knowing what data you're going to get, in what order, and whether or not the found entries are "before" or "after" your mentioned percentage.
Instead, my answer will be a method that recalculates all percentages of a given ID. This seems like a much clearer algorithm.
The assumed answer
Retrieving the data
Your attempt is a weird mix of new and old technologies (LINQ, DataTable), I'm going to use LINQ near exclusively, as I feel the use of DataTable is unwarranted here.
public static void CalculatePercentagesForID(int id)
{
Foo[] rows = db.Table.Where(x => x.ID == id).ToArray();
//... (see the next code block)
}
This is much simpler. Note that I am assuming that you wish to process the entries based on the order that they appear in the database. If you need to order them based on something else (e.g. a date value in your Foo objects), then you will have to use an additional OrderBy, e.g. :
Foo[] rows = db.Table.Where(x => x.ID == id).Orderby(x => x.DateCreated).ToArray();
Processing the data
It's important to notice here that a percentage is calculated off of two (subsequent) rows.
//The first entry is always the "base" price, therefore always 0.
rows[0].Percentage = 0;
for(int i = 1; i < rows.Length; i++)
{
var previous = rows[i-1];
var current = rows[i];
current.Percentage = CalculateDifferenceInPercentage(previous.Price, current.Price);
}
//TODO: save all the objects in "rows" back to the database!
Notice how the for loop starts at 1, not at 0. We skip step 0 because the first element is automatically 0 anyway. The for loop will only process every row after the first.
Calculating the percentage
public static Decimal CalculateDifferenceInPercentage(decimal oldPrice, decimal newPrice)
{
//1.The elaborate calculation
//The comments are example output when oldPrice = 19.21, newPrice = 19.79
var theRatio = newPrice / oldPrice;
// = 1.0301...
var theRatioRounded = Math.Round(theRatio,2);
// = 1.03
var thePercentageDifference = theRatioRounded - 1;
// = 0.03
return thePercentageDifference;
}
Or, if you want a shorter (but harder to read) version:
public static Decimal CalculateDifferenceInPercentage(decimal oldPrice, decimal newPrice)
{
return Math.Round(newPrice / oldPrice , 2) - 1;
}
Some caveats
I've omitted some null-checks for the sake of simplicity, e.g. checking if any rows are returned.
I've omitted how to save the updated entities in the database as it is not pertinent to your actual question about calculating the percentages.
This works both for negative and positive percentages.
I have 3 NumericUpDown elements in my form. This elements is synchronized by their sum. For example sum is 9 elements values is 3,3,3 and increment is 2. When user is changed first element up from 3 to 5 we must get 5,2,2.
For synchronized I had tried to use events ValueChanged and VisibleChanged, but they working when we have a programmatic modification or user interaction.
I used this method for every element, but for this events this method starts changing again, when result values other elements is changing in a code.
private void numericUpDown1Change(object sender, EventArgs e)
{
int oldValue = Sum - (int)numericUpDown2.Value - (int)numericUpDown3.Value;
int average;
if ((int)numericUpDown1.Value - oldValue > 0)
{
average = ((int)numericUpDown1.Value - oldValue) / 2;
numericUpDown2.Value = numericUpDown2.Value - average;
numericUpDown3.Value = numericUpDown3.Value - average;
}
else
{
average = (oldValue - (int)numericUpDown1.Value) / 2;
numericUpDown2.Value = numericUpDown2.Value + average;
numericUpDown3.Value = numericUpDown3.Value + average;
}
}
I want to use event, what worked just when user clicking the up or down button, or by the user entering a new value.
What event I must choose for it?
Use the ValueChanged event, but keep a flag telling you if the change is done by code or by user.
For a single control you can keep a Boolean variable at the class level (I would probably call it IsValueChangedByCode) and set it to false. Inside your methods, right before you change the value, set it to true and right after that back to false. Inside the event handler check that flag is true or false, and decide if you want to execute the code or not.
For 3 controls the logic is the same, but instead of using a boolean flag, you need 2 different booleans, or you can use an integer or flags enum.
I am trying to figure out a way to get the Computer player to respond to my moves basically by seeing "This spot is taken, I should see if another is free and take it".
So far, I'm not making any improvements (been like 5 hours). I want the computer to realize if a certain button (which it chose at random) is taken, it should consider another choice. Not sure where the if/else should actually go or where/what I should put in for it to try another location.
Here's the snippet of code with comments on my idea (likely wrong placement where I want to do things):
if (c.Enabled == true) //if the button is free
{
if ((c.Name == "btn" + Convert.ToString(RandomGenerator.GenRand(1, 9)) )) //if a specific button is free
{
if ((c.Text != "X")) //if its empty
{
//do this
c.Text = "O"; //O will be inside the button
c.Enabled = false; //button can no long be used
CheckComputerWinner(); //check if it finishes task
return;
}
else //if it is an X
{
//try a different button choice instead
//see if that button is empty
//do stuff
//else
//... repeat until all buttons are checked if free
}
}
}
My question is simply: How can I fix this and understand what is going on? Or do it more efficiently?
You could create an array with those buttons so you don't have to check names:
Button[9] gameField;
Creating a [3,3] array might be more intuitive, but for this case a plain array is easier to work with.
Then, you could count how many of them are free:
int freeCount = gameField.Count(b => b.Text != "X");
If you want to randomly select one of the free ones, generate a random number in the range 0 - (freeCount - 1) and select the appropriate button:
int offset = RandomGenerator.GenRand(0, freeCount - 1);
Button target = gameField.Where(b => b.Text != "X").Skip(offset).FirstOrDefault();
if (target != null) {
// check it
}
The extension method Where filters your buttons to only return the free ones. Skip will skip the specified number of elements (for random selection) and FirstOrDefault returns the first element of the resulting sequence (or null if there is none).
Note: You might want to check for some cases before randomly selecting a field to make your AI a bit more ambitious:
Has the computer player two O in a row with the third field being free? If so, select that one.
Has the human player two X in a row with the third field being free? If so, select that one.
There are tricks to exploit that strategy and there are also better heuristics, but i'll leave that to you.
Your looking for a while loop here. You can modify your code as follows:
Button c;
// here you look for a Button within the Controls of your Form. It stops when an Enabled Button with Text != "X" is found
do
{
c = this.Controls.Find("btn" + Convert.ToString(RandomGenerator.GenRand(1, 9)), true).FirstOrDefault() as Button;
} while (c == null || !c.Enabled || c.Text == "X");
c.Text = "O"; //O will be inside the button
c.Enabled = false; //button can no long be used
CheckComputerWinner(); //check if it finishes task
return;
I'm new to C#, trying to make a program that is essentially a survey with 30 questions that are answered by selecting one of five radio buttons (Strongly Disagree, Disagree...Strongly Agree, etc).
I have set up a small "block" of code that will check which radio button is checked for the question and assign a value to an array (see below).
namespace WindowsFormsApplication1
{
public partial class Form1 : Form
{
public Form1()
{
InitializeComponent();
}
private void buttonScore_Click(object sender, EventArgs e)
{
this.textBoxScoreOutput.Text = " ";
int[] score = new int[2]; // Declares the integer of score and sets it to a value of zero
// Question 1
if (radioButtonSD1.Checked == true) // If Strongly Disagree checked give score a value of 1
score[0] = 1;
else if (radioButtonD1.Checked == true) // If Disagree checked give score a value of 2
score[0] = 2;
else if (radioButtonNS1.Checked == true) // If Not Sure checked give score a value of 3
score[0] = 3;
else if (radioButtonA1.Checked == true) // If Agree checked give score a value of 4
score[0] = 4;
else if (radioButtonSA1.Checked == true) // If Strongly Agree is checked give score a value of 5
score[0] = 5;
// Question 2
if (radioButtonSD2.Checked == true) // If Strongly Disagree checked give score a value of 1
score[1] = 1;
else if (radioButtonD2.Checked == true) // If Disagree checked give score a value of 2
score[1] = 2;
else if (radioButtonNS2.Checked == true) // If Not Sure checked give score a value of 3
score[1] = 3;
else if (radioButtonA2.Checked == true) // If Agree checked give score a value of 4
score[1] = 4;
else if (radioButtonSA2.Checked == true) // If Strongly Agree is checked give score a value of 5
score[1] = 5;
// Output values in array to text box
this.textBoxScoreOutput.Text = "Array: ";
foreach (int i in score)
{
this.textBoxScoreOutput.Text += "[" + i.ToString() + "] ";
}
int sum = score.Sum();
this.textBoxScoreOutput.Text += "The Sum of the array is: " + sum.ToString();
}
}
}
So this is checking the first two of the thirty questions and is working exactly how I need it to and thought it would.
I was wondering if I could loop just one of these "blocks" and have it check all thirty questions. I have searched and searched but can't find exactly what I am looking for (I also understand I may not be searching for the right thing either).
I am just trying to avoid having thirty of these "blocks" in my program. I feel like it would just be a mess with thirty of these. Is this possible?
Start with creating a UserControl which encapsulates the logic for a single question:
Question Text
Selected option
Once you have a single question working, you can drop any number of User Controls on to a form, configure the question text and then only have to loop through the set of user controls to get your answers. The answer would be best returned as an enumeration.
There are a number of ways to achieve this, such as code to generate the controls, or binding the selections back to a ViewModel class, but a user control is a great start.
Here's how I do it roughly:
var resultList = new List<KeyValuePair<string, int>>();
foreach (var control in this.Controls)
{
if (control is GroupBox)
{
GroupBox gb = (GroupBox)control;
foreach (Control controll in gb.Controls)
{
if (controll is RadioButton)
{
RadioButton rb = new RadioButton();
rb = (RadioButton)controll;
//rb will allow you to access all of the RadioButton's properties and act accordingly.
if (rb.Checked)
{
int score;
if (rb.Name.Contains("ButtonSD"))
score = 1;
if (rb.Name.Contains("ButtonD"))
score = 2;
//So on...
resultList.Add(new KeyValuePair<string, int>(gb.Name, score));
}
}
}
}
}
Had a rough day so maybe someone can come up with something better, but if you don't feel like reorganizing the whole thing, this might work.
There's a form with three checkboxes and a button. Upon clicking on the button a messagebox is suppose to show up and display all the items that were checked on the form with price before tax and total. The price before tax and total are taken care of, but how would I display what was checked by the user on that form in the message box that will serve as a bill.
if (checkCheeseSnackBread.Checked == true)
{
price += 10;
items += "Cheese Snack Bread - $10";
}
else
{
price -= 10;
}
Just need some guidance.
First I must say that the code you've written seems to hold a logical eror. If the checkbox isn't checked then you shouldn't do anything. In your code you subtract the item-price from the total price. This way you give a discount of 10. If they don't buy it, don't add it. That's all.
So, now you know what they've bought, you can use a StringBuilder to populate the message.
Quick and dirty:
StringBuilder builder = new StringBuilder();
builder.AppendLine("Ticket")
builder.AppendLine();
if (checkCheeseSnackBread.Checked) // == true is not needed
{
price += 10;
items += "Cheese Snack Bread - $10";
builder.AppendLine(Cheese Snack Bread - $10);
}
// Do the same for other checkboxes
// Add the totals
Messagebox.Show(builder.ToString());
There is an other way: loop through the controls on the form, if it's a checkbox ==> add the text to the StringBuilder. This way it doesn't matter how much checkboxes there are. You just have to make sure that the text-property is used to print on the ticket (messagebox).
If you just want to display a string you generate.
Check this out:
http://msdn.microsoft.com/en-us/library/system.windows.forms.messagebox.aspx