C# Loop checkbox and add value - c#

I'm trying to add values of phones numbers based on checkbox's in the UI.
For example if a checkbox1 (which represent phone1) is checked and checkbox2 is also checked then the program will add both phones' values.
How can I add the value (in for loop for example) so that the if statement is lesser and simplified.
Here is my code:
public double totalPhone()
{
double total = 0;
double item1 = 2249;
double item2 = 1769;
double item3 = 3099;
double item4 = 1198;
double item5 = 1899;
if (chkPhone1.Checked == true)
{
total = total + item1;
}
if (chkPhone2.Checked == true)
{
total = total + item2;
}
if (chkPhone3.Checked == true)
{
total = total + item3;
}
if (chkPhone4.Checked == true)
{
total = total + item4;
}
if (chkPhone5.Checked == true)
{
total = total + item5;
}
return total;
}

Assuming these checkbox's are all in the same GroupBox control just loop over the controls in that specific groupbox. I tested this and it seems to work. Use the checkbox item's Tag property to store the value associated to it:
public partial class Form1 : Form
{
private static double Total { get; set; }
private void Form1_Load(object sender, EventArgs e)
{
var ctrl = groupBox1;
foreach (var checkBox in ctrl.Controls.OfType<CheckBox>())
{
Total = checkBox.Checked ? (Total + Convert.ToDouble(checkBox.Tag)) : Total;
}
}
}

I'm sure there is some re-factoring required on your code, but I don't see any case to use loop for this simple case.
Still interested? You could do something like this. Please note this code assume one to one mapping between item and checkbox name.
Dictionary<string, int> values = new Dictionary<string,int>();
int total = 0;
values.Add("item1", 2249);
values.Add("item2", 1769);
values.Add("item3", 3099);
values.Add("item4", 1198);
values.Add("item5", 1899);
foreach( CheckBox cb in this.Controls.OfType<CheckBox>()
.Where(c=>c.Checked))
{
int itemprice;
if(values.TryGetValue("item"+ Regex.Match(cb.Text, #"\d+").Value, out itemprice))
{
total+=itemprice;
}
}

You can store the ids of the checkboxes and its corresponding values in a Dictionary and then loop through the controls,check for its type and checked property and then add the value corresponding to the id of the checkbox from the dictionary.
Note:Code is not tested but this should get you on the way.
public double totalPhone()
{
double total = 0;
Dictionary<string,double> items = new Dictionary<string,double>();
items.Add(chkPhone1.ID,2249); // ID,Text whatever works
items.Add(chkPhone2.ID,1769);
items.Add(chkPhone3.ID,3099);
items.Add(chkPhone4.ID,1198);
items.Add(chkPhone5.ID,1899);
foreach(Control c in this.Controls)
{
if(c is CheckBox && c.Checked)
{
total += (items[c.ID] != null ? items[c.ID] : 0);
}
}
return total;
}

Related

How to get sum of selected DataGrid values in a C# WPF app?

I have a C# WPF app, and my goal is to get the sum of selected row values from a DataGrid, and set a textbox with this total. This sum calculation is triggered by an event that detects when the selected items have changed.
The problem is that when I select many rows at once or select all with Ctrl + A, I get unpredictable sum values.
To troubleshoot, I bound the datagrid with 100 rows, each with an amount of 1. I then selected all items with Ctrl + A. The total sum should be 100, but it caps at 7 or 8 units.
Below is what I have so far. Anyone see the problem?
private void DgDailyTransactions_SelectedCellsChanged(object sender, SelectedCellsChangedEventArgs e)
{
decimal sum = 0;
for (int i = 0; i < dgDailyTransactions.SelectedItems.Count; i++)
{
TextBlock tb = dgDailyTransactions.Columns[1].GetCellContent(dgDailyTransactions.SelectedItems[i]) as TextBlock;
if (tb != null)
{
sum += Convert.ToDecimal(tb.Text);
}
}
tbxSelectedDailyTransactionsTotal.Text = sum.ToString();
}
Suppose your class looks like this:
public class Sales
{
public int Order { get; set; }
public decimal Amount { get; set; }
}
Make a simple method as under:
private void FindAmount()
{
decimal totalSum = 0;
//Add amounts of selected
if (MyDTGRID.SelectedItems.Count > 0)
{
for (int i = 0; i <= dgDailyTransactions.SelectedItems.Count - 1; i++)
{
Sales sales = dgDailyTransactions.SelectedItems[i] as Sales;
decimal amount = sales.Amount;
totalSum += amount;
}
}
myTextBlock.Text = totalSum.ToString();
}
Simply call the method in your selectedCellsChanged Event
private void DgDailyTransactions_SelectedCellsChanged(object sender, SelectedCellsChangedEventArgs e)
{
FindAmount();
}
I hope this helps.
for the sum method you can do it using linq (if you don't know I strongly advise you to learn linq, very strong tool in C#), also would advise you to use MVVM, will make your code much easier to debug in future :
private void dgDailyTransactions_SelectionChanged(object sender, SelectionChangedEventArgs e)
{
List<Sales> myList=dgDailyTransactions.SelectedItems.Cast<Sales>();
decimal totalSum = 0;
if (myList.Count() > 0)
{
totalSum = myList.Sum(item => item.Amount);
}
myTextBlock.Text = totalSum.ToString();
}
in MVVM (if you use it) you would need just that line in Model :
private void dgDailyTransactions_SelectionChanged(object sender, SelectionChangedEventArgs e)
{
contexte.SelectedSales= new ObservableCollection<Sales>(dgDailyTransactions.SelectedItems.Cast<Affaire>());
}
then you use formula in your ViewModel in set section of SelectedSales

C# Multiplying the values of an array together which are loaded from a textfile into a List<>

So I have an array, strArray, that stores the values of my text files which has 3 columns. I think this is called a two or three dimensional array, not sure. Or maybe one dimensional. I have a List<> called Inventory which adds the data to it.
I currently have three successful columns I just need the fourth. The fourth column is the second and third column multiplied together, which is a total price. The second column is an int, "Number of Items", the third is a decimal, "Price" and the fourth is a decimal, "Total Price" which is Number of Items * Price.
I'll go ahead and post my code, I am also using four list boxes for the data. Three columns (or three list boxes) work fine, but I just gotta get the fourth one figured out.
Sorry for the large amount of code, I figured if I copied all of it it'll make it easier to see if an error occurred earlier on. btnLoadInfo_Click is the event/method where the main issue is.
namespace TCSCapstone
{
public partial class frmInventory : Form
{
List<frmInventory> Inventory = new List<frmInventory>();
public frmInventory()
{
InitializeComponent();
}
public string ItemName { get; set; }
public int NumberOfItems { get; set; }
public decimal Price { get; set; }
public decimal TotalPrice { get; set; }
string selectedList = "";
private void cmbList_SelectedIndexChanged(object sender, EventArgs e)
{
selectedList = this.cmbList.GetItemText(this.cmbList.SelectedItem);
lstItemName.DataSource = null;
lstNumberOfItems.DataSource = null;
lstPrice.DataSource = null;
lstItemName.Items.Clear();
lstNumberOfItems.Items.Clear();
lstPrice.Items.Clear();
lstTotalPrices.Items.Clear();
if (selectedList == "Creative Construction")//if the selected combo box item equals the exact string selected
{
selectedList = "creative"; //then the string equals creative, which is creative.txt but I add the .txt in the btnLoadInfo method
} else if (selectedList == "Paradise Building")
{
selectedList = "paradise";//this is for paradise.txt
}
else if (selectedList == "Sitler Construction")
{
selectedList = "sitler";//this is for sitler.txt
}
else
{
MessageBox.Show("Please select one of the items.");
}
}`
private void btnLoadInfo_Click(object sender, EventArgs e)
{
Inventory.Clear(); //Clears the entire Inventory List
using (StreamReader invReader = new StreamReader(selectedList +
".txt"))
{
while (invReader.Peek() >= 0)
{
string str;
string[] strArray;
str = invReader.ReadLine();
strArray = str.Split(',');
frmInventory currentItem = new frmInventory();
currentItem.ItemName = strArray[0];
currentItem.NumberOfItems = int.Parse(strArray[1]);
currentItem.Price =
decimal.Parse(strArray[2]);
strArray[1].
currentItem.TotalPrice = decimal.Parse(strArray[1] *
strArray[2]);
Inventory.Add(currentItem);
}
}
displayLists(); //Calls the displayLists method to update list
//boxes at the end of the button click event
}//end of btnLoadInfo
void displayLists()
{
//Resets the listboxes datasources by setting them to null
lstItemName.DataSource = null;
lstNumberOfItems.DataSource = null;
lstPrice.DataSource = null;
lstItemName.Items.Clear();
lstNumberOfItems.Items.Clear();
lstPrice.Items.Clear();
lstTotalPrices.Items.Clear();
lstItemName.DisplayMember = "ItemName";
lstItemName.ValueMember = "";
lstItemName.DataSource = Inventory;
lstNumberOfItems.DisplayMember = "NumberOfItems";
lstNumberOfItems.ValueMember = "";
lstNumberOfItems.DataSource = Inventory;
lstPrice.DisplayMember = "Price";
lstPrice.ValueMember = "";
lstPrice.DataSource = Inventory;
}
Your TotalPrice property should be a mathematical equation, not something you set independently of the number of items and their prices.
Change the property to this:
public decimal TotalPrice{
get{ return NumberOfItems * Price; }
}
Delete the line that sets TotalPrice in your loop; it's no longer necessary because you've set the item price and the number of items; the total price inherently follows from these
You're trying to multiply two strings together. Instead, multiply the numeric values that you have already parsed:
currentItem.TotalPrice = currentItem.NumberOfItems * currentItem.Price;

ComboBox and TextBox with Same Functions

Good day To All, i was wondering is there any possibility
Winform Items
A.) 1~5 ComboBox
B.) 1~5 Textbox for Time (i'll identify them for example as txtTime1 ~ txtTime5)
C.) 1~5 Textbox for Amount (i'll identify them for example as txtAmount1 ~ txtAmount5)
Items 1 ~ 5 (ComboBox 1-5 , txtTime 1-5, txtAmount 1-5) will do the same Functions.
A.)
if (combobox1.SelectedValue.ToString() == "Regular")
{
x = 1.25;
}
else if (combobox1.SelectedValue.ToString() == "Double")
{
x = 2;
}
// Same Codes for ComboBox 2~5
B.)Textbox "txtTime(s)" will hold a TextChange Event fetching values of our said comboBoxes
if (txtTime.Text.Lenght > 0)
{
// Item Letter "C"
// value of "x" is equal to the above item
txtAmount.Text = (double.Parse(txtTime.Text) * x).ToString();
}
i just need a quick idea on how will i make this work
Thank You in Advance
Edit*
All i can think of is calling them 1 by 1 just a quick code
private Method1()
{ double x,base;
if (combobox1 = "Regular")
{ x = base * 1.25; }
if (combobox2 = "Regular")
{ x = base * 1.25; }
// so on
return x;
}
private txtTime1_TextChange(Event ****)
{
if (txtTime1.Text.Lenght > 0)
{ txtAmount1.Text = (Method1() * double.Parse(txtTime1.Text)).ToString();}
private txtTime2_TextChange(Event ****)
{
if (txtTime2.Text.Lenght > 0)
{ txtAmount2.Text = (Method1() * double.Parse(txtTime2.Text)).ToString();}
// and so on
You can have a method as your controls event handler .Each event handler has a sender argument that represent the control that the event has fired for.
You can have a event handler like this :
public ComboBoxEventHandler(object sender,EventArgs args)
{
var comboBox=sender as ComboBox;
if(comboBox==null) return;
if (comboBox.SelectedValue.ToString() == "Regular")
{
x = 1.25;
}
else if (comboBox.SelectedValue.ToString() == "Double")
{
x = 2;
}
}}
You can do the same thing for other controls.
UPDATE
To make things easier to maintain you can have a class that contains corresponding controls and their behaviors then you can add your controls dynamically to your form without having to repeat yourself or you can add more rows to your form very easily .Take something like this for example:
public class RowController
{
public ComboBox Rate{get;private set;}
public TextBox Hours{get;private set;}
public TextBox Amount{get;private set;}
public RowController(ComboBox rate,TextBox hours,TextBox amount)
{
Rate=rate;
Hours=hours;
Hours.TextChange+=OnHoursChanged;
Amount=amount;
}
private void OnHoursChanged(object sender,EventArgs args)
{
if (Hours.Text.Length > 0)
{ Amount.Text = (GetRate() * double.Parse(Hours.Text)).ToString();}
}
private double GetRate()
{
if (Rate.SelectedValue.ToString() == "Regular")
{
return 1.25;
}
else if (Rate.SelectedValue.ToString() == "Double")
{
return 2;
}
}
}
Then you can define RowControllers in your form like this :
var row1=new RowController(comboBox1,txtTime1,txtAmount1);
and each controller will do its job by its own.

List order (or iteration) malfunction

Hello I am having trouble with an iteration through a list of 17 labels:
for (int i = 0; i < labels.Count - 1; i++)
{
MessageBox.Show(labels[i].Name);
if (labels[i].Visible == false && labels[i + 1].Visible == true)
{
...
Here are the results I get:
First it goes from label10 to label17, and then in descending order from label9 to label2.
Here is how I add the labels to the list:
private void newGameToolStripMenuItem_Click(object sender, EventArgs e)
{
foreach (Control c in this.Controls)
{
if (c is Label)
{
labels.Add(c);
c.Enabled = true;
if (c.Visible == false)
{
c.Visible = true;
}
}
}
}
I want it to go from label1 to label16, since the loop is just a loop I guess the problem lies in the order in which the labels were added to the list, but I am not sure how to fix it.
Your main problem is lexicographic order which is inherently used when you sort by Name of the label, what you want is to sort by numbers after the term label. In that case, first sort the labels list and then run the for statement over it, check the code:
var lst = labels.OrderBy(x => int.Parse(x.Name.Substring("label".Length))).ToList();
for (int i = 0; i < lst.Count - 1; i++)
{
MessageBox.Show(lst[i].Name);
...
But have in mind that this code is simple and presumes that label Name property always starts with "label" string. If that can change you must handle that case.
I guess you want to sort the labels according to their names?
labels.Sort((x, y) => { return x.Name.CompareTo(y.Name); });
but what are the difference between:
Show "Label 1" first, then "Label 2", and
Show "Label 2" first, then "Label 1"?
Check the designer.cs file to see in which order the labels are added to the Form
assuming that you have Labels id as Label1,Label2..........,Label16
in order to get the labels serially you have to write the following code
labels = labels.ConvertAll<Control>(GetIdFromLabel);
labels.Sort((x, y) => { return x.Id.CompareTo(y.Id); });
public Control GetIdFromLabel(Control c)
{
c.Id = c.Name.Replace("Label", "") == "" ? 0 : Convert.ToInt32(c.Name.Replace("Label", ""));
return c;
}
add this class in your code also
public class Control
{
public string Name { get; set; }
public int Id { get; set; }
}
Try this out:
private void newGameToolStripMenuItem_Click(object sender, EventArgs e)
{
labels.Clear();
Control[] matches;
for (int i = 1; i <= 16; i++)
{
matches = this.Controls.Find("label" + i.ToString(), true);
if (matches.Length > 0 && matches[0] is Label)
{
Label lbl = (Label)matches[0];
labels.Add(lbl);
lbl.Enabled = true;
if (lbl.Visible == false)
{
lbl.Visible = true;
}
}
}
}

How to calculate the one particular column total by differentiating items?

I Have a DataGridView, with columns Item, description, quantity, rate & total.
I have two types of items, one item have vapasi == yes (vapasi is a kind of deposite amount), & another item have vapasi == No.I want to calculate the sum of 'total' column by differentiating items with vapasi & items without vapasi, & want to display this calculated total into two respective textboxes that is 'txtboxwithvapasi', n 'txtboxwithoutvapasi' which are there after the grid.I did following code :
private void grdPurchase_CellEndEdit_1(object sender, DataGridViewCellEventArgs e)
{
try
{
try
{
string value = grdPurchase.Rows[e.RowIndex].Cells[e.ColumnIndex].Value.ToString();
if (e.ColumnIndex == 2)
{
int val = int.Parse(value);
quantity = val;
}
if (e.ColumnIndex == 4)
{
float val = float.Parse(value);
total = val;
if (vapasi1 == "Yes")
{
vtot += total; //vtot=0+10
txt_forvapasitotal.Text = vtot.ToString(); //10
float vapsitot =float.Parse(txt_forvapasitotal.Text);
float vapsicalculate = (vapsitot * a);
float tax = vapsicalculate / 100;
float with_vapasi = vtot + tax;
txt_withvapasi.Text =Convert.ToString(with_vapasi);
}
else
{
nvtot = 0;
for (int i = 0; i < grdPurchase.Rows.Count; i++)
{
if (vapasi1 == "No")
{
if (grdPurchase.Rows[e.RowIndex].Cells[3].Selected == true)
{
nvtot += float.Parse(grdPurchase[4, i].EditedFormattedValue.ToString());
txt_withoutvapasitot.Text = nvtot.ToString();
}
}
}
}
txt_vapasiincludedtot.Text =(float.Parse(txt_withvapasi.Text) +float.Parse(txt_withoutvapasitot.Text)).ToString();
}
if (e.ColumnIndex == 1)
{
int val = int.Parse(value);
materialid = val;
string vapasi = "Select material_vapasi from tbl_material_master where active_flag=1 AND material_id =" + materialid + "";
SqlCommand cmd = new SqlCommand(vapasi, con);
sdr = cmd.ExecuteReader();
if (sdr.HasRows)
{
while (sdr.Read())
{
vapasi1 = sdr["material_vapasi"].ToString();
}
}
}
}
catch (Exception ex)
{
MessageBox.Show(ex.Message.ToString());
}
grdPurchase.Columns[3].ReadOnly = false;
}
catch (Exception ex)
{
MessageBox.Show(ex.Message.ToString());
}
}
Problem is:-when I am selecting item with vapasi in first row & in second row item without vapasi , its working properly.But if i Select any item at third row ,then its doing sum of all the three items in 'txtboxwithoutvapasi' without differentiating items.
You need to keep track of vapasi being "Yes" or "No" for each row in the grid, but you are using a single variable. Can't you add this column to the grid (as a hidden column if you don't want to show this to the user)? Then whenever you need to calculate the totals you simply iterate through the grid rows and check the vapasi column in stead of the vapasi1 variable.

Categories

Resources