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.
Related
I have two columns in Datagridview, one for the price excluding Vat and another one for price including Vat, I want it to be dynamic, if I alter the price excluding vat it updates the column including Vat, and if I Update the including Vat column it updates the excluding VAT column vice-versa.
I would appreciate if anyone can help me with the right code for it in C#.
Here´s the code I´m using the calculation to one direction I need the code for the inverse.
private void dgv_Filho_CellEndEdit_1(object sender, DataGridViewCellEventArgs e)
{
bool Check = Convert.ToBoolean(dgv_Filho.CurrentRow.Cells["Check_Filho"].Value);
string Medida_1 = Convert.ToString(dgv_Filho.CurrentRow.Cells["Medida_1"].Value);
string Medida_2 = Convert.ToString(dgv_Filho.CurrentRow.Cells["Medida_2"].Value);
var Iva = Convert.ToDecimal(cb_Iva.Text);
if (Check)
{
if (!string.IsNullOrWhiteSpace(tb_CodigoArtigo.Text) || !string.IsNullOrWhiteSpace(tb_Descricao.Text))
{
dgv_Filho.CurrentRow.Cells["ArtigoPai"].Value = tb_CodigoArtigo.Text;
dgv_Filho.CurrentRow.Cells["Descricao_Pai"].Value = tb_Descricao.Text + " " + Medida_1 + Medida_2;
dgv_Filho.CurrentRow.Cells["CodigoArtigoFilho"].Value = tb_CodigoArtigo.Text + Medida_1 + Medida_2;
//dgv_Filho.CurrentRow.Cells["PrecoFilhoSemIva"].Value = tb_PVP1.Text;
decimal PrecoFilho = Convert.ToDecimal(dgv_Filho.CurrentRow.Cells["PrecoFilhoSemIva"].Value);
if (PrecoFilho > 0)
{
decimal PrecoFilhoComIva = PrecoFilho * Iva / 100 + PrecoFilho;
dgv_Filho.CurrentRow.Cells["PrecoFilhoComIva"].Value = PrecoFilhoComIva;
}
}
else
{
dgv_Filho.CurrentRow.Cells["ArtigoPai"].Value = string.Empty;
dgv_Filho.CurrentRow.Cells["Descricao_Pai"].Value = string.Empty;
}
}
}
This isn't too difficult using your existing code:
First of all, use the name of the edited column in if/else if statements to filter which conversion should take place, so that changing the VAT column doesn't get overwritten by the preVAT column. Then, use the opposite algebraic expression of the one you already have written to convert the postVAT price back to the preVAT
Here is what it will look like:
dgv_Filho.CurrentRow.Cells["ArtigoPai"].Value = tb_CodigoArtigo.Text;
dgv_Filho.CurrentRow.Cells["Descricao_Pai"].Value = tb_Descricao.Text + " " + Medida_1 + Medida_2;
dgv_Filho.CurrentRow.Cells["CodigoArtigoFilho"].Value = tb_CodigoArtigo.Text + Medida_1 + Medida_2;
decimal PrecoFilho = Convert.ToDecimal(dgv_Filho.CurrentRow.Cells["PrecoFilhoSemIva"].Value);
decimal PrecoFilhoComIva = Convert.ToDecimal(dgv_Filho.CurrentRow.Cells["PrecoFilhoComIva"].Value);
if (dgv_Filho.Columns[e.ColumnIndex].Name == "PrecoFilhoSemIva")
{
PrecoFilhoComIva = PrecoFilho * (Iva / 100) + PrecoFilho;
dgv_Filho.CurrentRow.Cells["PrecoFilhoComIva"].Value = PrecoFilhoComIva;
}
else if (dgv_Filho.Columns[e.ColumnIndex].Name == "PrecoFilhoComIva")
{
decimal PrecoFilhoSemIva = PrecoFilhoComIva - (PrecoFilhoComIva / (1 + (Iva / 100)) * (Iva / 100));
dgv_Filho.CurrentRow.Cells["PrecoFilhoSemIva"].Value = PrecoFilhoSemIva;
}
Using this code, editing the preVAT value will automatically update the postVAT value accordingly, and editing the postVAT value will automatically update the preVAT value accordingly
Rather than interact with the DataGridView directly (which can be complex) you could instead make a class that implements INotifyPropertyChanged and keeps all of its internal calculations up-to-date at all times (which is easier). Here is a simplified version of such a class that responds to changes of Descricao, Medida and PrecoFilhoSemIva.
Simplified class that represents a row of data
class Articulo : INotifyPropertyChanged
{
public event PropertyChangedEventHandler PropertyChanged;
protected virtual void OnPropertyChanged([CallerMemberName] string propertyName = null)
{
PropertyChanged?.Invoke(this, new PropertyChangedEventArgs(propertyName));
}
string _descricao = string.Empty;
public string Descricao
{
get => _descricao;
set
{
if (!Equals(_descricao, value))
{
_descricao = value;
OnPropertyChanged();
}
}
}
public string Descricao_Pai => $"{Descricao} {Medida_1}#{_precoFilhoSemIva.ToString("F2")}";
public decimal PrecoFilhoComIva => _precoFilhoSemIva * (1.0m + MainForm.Iva);
decimal _medida = 0;
public decimal Medida
{
get => _medida;
set
{
if (!Equals(_medida, value))
{
_medida = value;
OnPropertyChanged();
}
}
}
decimal _precoFilhoSemIva = 0;
public decimal PrecoFilhoSemIva
{
get => _precoFilhoSemIva;
set
{
if (!Equals(_precoFilhoSemIva, value))
{
_precoFilhoSemIva = value;
OnPropertyChanged();
}
}
}
string _codigoArtigo = System.Guid.NewGuid().ToString().Substring(0, 10).ToUpper();
public string CodigoArtigo
{
get => _codigoArtigo;
set
{
if (!Equals(_codigoArtigo, value))
{
_codigoArtigo = value;
OnPropertyChanged();
}
}
}
}
Instances of this class are placed in a BindingList which is assigned to the DataSource property of dgv_Filho and caused the DGV to update whenever the Refresh method is called.
Initializations
The only interaction that should be necessary with the DGV is to initialize the columns and bindings properly in the MainForm override for the Load event. This is also where we bind the combo box to a static value for Iva that can be used by the calculation for the row items.
protected override void OnLoad(EventArgs e)
{
base.OnLoad(e);
initDataGridView();
initComboBox();
}
private void initDataGridView()
{
dgv_Filho.DataSource = DataSource;
DataSource.ListChanged += (sender, e) =>
{
if (e.ListChangedType == ListChangedType.ItemChanged)
{
dgv_Filho.Refresh();
}
};
// Add one or more items to autogenerate the columns.
Random randomPriceGen = new Random(1);
for (int i = 1; i <= 3; i++)
{
var preco = i == 1 ? 1.0m : (decimal)randomPriceGen.NextDouble() * 100;
DataSource.Add(new Articulo
{
Descricao = $"Articulo {(char)('A' + (i - 1))}",
Medida = i,
PrecoFilhoSemIva = preco,
});
}
// Do a little column formatting
foreach (DataGridViewColumn column in dgv_Filho.Columns)
{
switch (column.Name)
{
case nameof(Articulo.Descricao):
column.AutoSizeMode = DataGridViewAutoSizeColumnMode.Fill;
column.MinimumWidth = 120;
break;
case nameof(Articulo.Medida):
case nameof(Articulo.PrecoFilhoSemIva):
case nameof(Articulo.PrecoFilhoComIva):
column.DefaultCellStyle.Format = "F2";
column.AutoSizeMode = DataGridViewAutoSizeColumnMode.AllCells;
break;
default:
column.AutoSizeMode = DataGridViewAutoSizeColumnMode.AllCells;
break;
}
}
}
private void initComboBox()
{
cb_Iva.SelectedIndex = 0;
cb_Iva.SelectedIndexChanged += onIvaSelected;
cb_Iva.KeyDown += (sender, e) =>
{
if( e.KeyData == Keys.Enter)
{
e.Handled = e.SuppressKeyPress = true;
}
onIvaSelected(sender, e);
};
onIvaSelected(cb_Iva, EventArgs.Empty);
void onIvaSelected(object sender, EventArgs e)
{
if (decimal.TryParse(cb_Iva.Text.Replace("%", string.Empty), out decimal iva))
{
Iva = iva / 100m;
dgv_Filho.Refresh();
cb_Iva.BackColor = SystemColors.Window;
}
else cb_Iva.BackColor = Color.LightSalmon;
}
}
What I am trying to do is , I have made a Unit Converter. It has 2 comboBoxes (fromCb and toCB )and 2 Textboxes (fromTb and toTb ). What I want to do is for example if I select Kilometers in fromCB and enter a value in fromTB , and when I select Meters in toCB , I want the value to be calculated and shown in toTB as soon as I select Meters in toCB. With the code below the value is calculated if both the selections(Kilometers and meters are already made) and then I type a value in the fromTB. I want to make only one selection that is only the fromCB selection (Kilometers)and type value for it and the calculation should be done whenever I change the toTB selections(Meters , centimeters).
EDIT —
My current program runs this way :
1- I select Kilometers to convert from
2- I select Meters to convert to
3 - I put value in Convert from textbox
4 - The value is converted and shown in convert to textbox
I have to select both the selections first and then it converts.
How I want it to run :
1- I select Kilometers to convert from
2- I put the value to convert from
3- I select meters / centimetres to convert to ( I can change it continuously and I want the value to be converted with it )
4- Value is converted and shown in convert to textbox
Here I want to select one selection , put the value and the conversion should show as I change the second selection
EDIT 2-
Ok see my code is working it has no error , its just not working the way i want to. What I want to do is. I want to select kilometers in fromCB and then put a value in fromTB. Now this is my input. Now for my output as soon as I select any selection (for example - meters) in toCB , the value should populate automatically into toTB , and if I change my output selection (for example centimeters) , it should populate automatically in toTB again without altering the input. What my code is doing is , I have to select both selections(Km and cm) and then when I input any value , the output is populated and if i want to change the output selection(for example to meters) the output value does not change automatically , I have to input the value again
if (fromCB.SelectedItem == "Kilometers [km]")
{
if (fromTB.Text == "")
{
MessageBox.Show("Please enter a value to convert");
}
if(toCB.SelectedItem=="Meters [m]")
{
float tb1;
float tb2;
tb1 = int.Parse(fromTB.Text);
tb2 = tb1 * 1000;
toTB.Text = tb2.ToString();
}
I think I have solution for you. You can use SelectedIndexChanged event for combobox. If you want update calculation on textchanged you can also use that update UI method. Please check the code->
public class MyType
{
public string Name { get; set; }
public int ID { get; set; }
}
void LoadData()
{
List<MyType> list = new List<MyType>();
list.Add(new MyType() { ID = 1, Name = "Centimeter" });
list.Add(new MyType() { ID = 2, Name = "Meter" });
list.Add(new MyType() { ID = 3, Name = "KiloMeter" });
fromCB.DataSource = list.ToList();
fromCB.DisplayMember = "Name";
fromCB.ValueMember = "ID";
toCB.DataSource = list.ToList();
toCB.DisplayMember = "Name";
toCB.ValueMember = "ID";
}
private void fromCB_SelectedIndexChanged(object sender, EventArgs e)
{
UpdateUI();
}
private void toCB_SelectedIndexChanged(object sender, EventArgs e)
{
UpdateUI();
}
void UpdateUI()
{
if (fromCB.SelectedItem != null && toCB.SelectedItem != null)
{
var fromID = ((MyType)fromCB.SelectedItem).ID;
var toID = ((MyType)toCB.SelectedItem).ID;
if (!string.IsNullOrEmpty(fromTB.Text) && !string.IsNullOrWhiteSpace(fromTB.Text))
{
float value = -1;
if (float.TryParse(fromTB.Text, out value))
{
if (fromID == toID)
{
toTB.Text = value.ToString();
}
else if (fromID == 1 && toID == 2)
{
toTB.Text = (value / 100).ToString();
}
else if (fromID == 1 && toID == 3)
{
toTB.Text = (value / 100000).ToString("0.#########");
}
else if (fromID == 2 && toID == 1)
{
toTB.Text = (value * 100).ToString();
}
else if (fromID == 2 && toID == 2)
{
toTB.Text = value.ToString();
}
else if (fromID == 2 && toID == 3)
{
toTB.Text = (value * 0.001).ToString();
}
else if (fromID == 3 && toID == 1)
{
toTB.Text = (value * 100000).ToString();
}
else if (fromID == 3 && toID == 2)
{
toTB.Text = (value * 1000).ToString();
}
else if (fromID == 2 && toID == 3)
{
toTB.Text = value.ToString();
}
}
else
{
MessageBox.Show("Input is not a number");
}
}
}
}
Note: This is little bit long code. Please check if I missed something.
I want to create a webform with 4 types of phones like: LG, xiaomi, samsung and iphone. They will be in an Array and I will insert them into dynamic radiobuttonList in the page init.
Also, the user will have a textbox where he will put an amount of money he has. The user will also have a button that will calc if he have the budget for the selected phone from the list.
After the user selects the phone, write in the budget and press the button
he will get "in budget" or "not enough budget".
The class have property of the array to insert the all the array from the page init and will have 2 functions:
One function will take the budget number > will go to the 2nd function that will see the selected phone and the budget > do its calcs and return the result into the 1st func that will give the feedback.
Now where I am stuck:
if the class isnt made global - and i put it in init or in button click - it wont work, so im looking for a way to make it work but without putting it global
so far i managed to inject the selected value into a class property and than compare - but i want to know if there is a way that this can happen with array inside class property
maybe if anyone can help me out and refer me to a guide where i can learn more about this subject (how inject selected value into function of a class and etc) ill be glad! as everything i see is C# with console but i work with ASP.NET WEB APPLICATION (.netframework)
enter code here
namespace gfjsr{
public partial class WebForm1 : System.Web.UI.Page{
phone InsertUserInfo = new phone();
protected void Page_init(object sender, EventArgs e){
string[] myArr = new string[] { "samsung", "IPHONE", "XIAOMI","LG"};
RadioButtonList phoneList = new RadioButtonList();
phoneList.ID = "radioList";
for (int i = 0; i< myArr.Length; i++)
{
ListItem li = new ListItem();
li.Text = myArr[i];
li.Value = i.ToString();
phoneList.Items.Add(li);
}
Panel1.Controls.Add(phoneList);
Label budgetLb = new Label();
budgetLb.ID = "budglb";
budgetLb.Text = "write your budget";
Panel1.Controls.Add(budgetLb);
TextBox insertBudg = new TextBox();
insertBudg.ID = "budgTxt";
Panel1.Controls.Add(insertBudg);
Button myBtn = new Button();
myBtn.ID = "btn1";
myBtn.Click += new EventHandler(btn1_click);
myBtn.Text = "result";
Panel1.Controls.Add(myBtn);
Label Labelfeedback = new Label();
Labelfeedback.ID = "feedback";
Labelfeedback.Text = "";
Panel1.Controls.Add(Labelfeedback);
}
protected void Page_Load(object sender, EventArgs e)
{
}
protected void btn1_click(object sender, EventArgs e)
{
InsertUserInfo.phoneChosen = ((RadioButtonList)FindControl("radioList")).SelectedItem.Text;
double UserBudget =
Convert.ToDouble(((TextBox)FindControl("budgTxt")).Text);
InsertUserInfo.BudgetYN(UserBudget);
((Label)FindControl("feedback")).Text = InsertUserInfo.feedback; }}}
namespace gfjsr{
public class phone{
private string _phoneChosen;
public string phoneChosen
{
get { return _phoneChosen; }
set { _phoneChosen = value; }
}
private string _feedback;
public string feedback
{
get { return _feedback; }
set { _feedback = value; }
}
public double Func1(string x)
{
double phonePrice = 0;
if( x == "samsung")
{
phonePrice = 4000;
}
if (x == "IPHONE")
{
phonePrice = 3500;
}
if (x == "XIAOMI")
{
phonePrice = 3000;
}
if (x == "LG")
{
phonePrice = 2000;
}
return phonePrice;
}
public void BudgetYN(double y)
{
if(y >= Func1(_phoneChosen))
{
_feedback = "positive";
}
else
{
_feedback = "no";
}
}
}
}
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;
}
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;
}
}
}
}