Add items to combobox with multiple values C# - c#

currently I have a combobox with three hard coded items.
Each item carries 2 values. I'm using a switch case statement to get the values for each item depending on which item is selected.
Switch(combobox.selectedindex)
{
case 0: // Item 1 in combobox
a = 100;
b = 0.1;
break;
case 1: // Item 2 in combobox
a = 300;
b = 0.5;
break;
//and so on....
}
I'm trying to add a feature to allow the user to add more items into the combobox with inputted a and b values. How would i be able to dynamically add case statements and define the values under each case condition? I've had a look at using a datatable instead but I don't know how to get multiple valuemembers out of the datatable when one item is selected.
Also, I would like to save the user added items and it's corresponding values to a .dat file. So when the program is re-opened it will be able to load the list of items added by the user from the file. I considered using streamwriter and readline for this but I'm unsure how it would be done.

You can use Binding on a combobox using the DataSource. The ComboBox can also be bound to other things than Primitive values (string/int/hardcoded values). So you could make a small class that represents the values you are setting in your switch statement, and then use the DisplayMember to say which property should be visible in the combobox.
An example of such a basic class could be
public class DataStructure
{
public double A { get; set; }
public int B { get; set; }
public string Title { get; set; }
}
Since you are talking about users adding values to the combobox dynamically, you could use a BindingList that contains the separate classes, this BindingList could be a protected field inside your class, to which you add the new DataStructure when the user adds one, and then automatically updates the combobox with the new value you added.
The setup of the ComboBox, can be done in either Form_Load, or in the Form Constructor (after the InitializeComponent() call), like such:
// your form
public partial class Form1 : Form
{
// the property contains all the items that will be shown in the combobox
protected IList<DataStructure> dataItems = new BindingList<DataStructure>();
// a way to keep the selected reference that you do not always have to ask the combobox, gets updated on selection changed events
protected DataStructure selectedDataStructure = null;
public Form1()
{
InitializeComponent();
// create your default values here
dataItems.Add(new DataStructure { A = 0.5, B = 100, Title = "Some value" });
dataItems.Add(new DataStructure { A = 0.75, B = 100, Title = "More value" });
dataItems.Add(new DataStructure { A = 0.95, B = 100, Title = "Even more value" });
// assign the dataitems to the combobox datasource
comboBox1.DataSource = dataItems;
// Say what the combobox should show in the dropdown
comboBox1.DisplayMember = "Title";
// set it to list only, no typing
comboBox1.DropDownStyle = ComboBoxStyle.DropDownList;
// register to the event that triggers each time the selection changes
comboBox1.SelectedIndexChanged += comboBox1_SelectedIndexChanged;
}
// a method to add items to the dataItems (and automatically to the ComboBox thanks to the BindingContext)
private void Add(double a, int b, string title)
{
dataItems.Add(new DataStructure { A = a, B = b, Title = title });
}
// when the value changes, update the selectedDataStructure field
private void comboBox1_SelectedIndexChanged(object sender, EventArgs e)
{
ComboBox combo = sender as ComboBox;
if (combo == null)
{
return;
}
selectedDataStructure = combo.SelectedItem as DataStructure;
if (selectedDataStructure == null)
{
MessageBox.Show("You didn't select anything at the moment");
}
else
{
MessageBox.Show(string.Format("You currently selected {0} with A = {1:n2}, B = {2}", selectedDataStructure.Title, selectedDataStructure.A, selectedDataStructure.B));
}
}
// to add items on button click
private void AddComboBoxItemButton_Click(object sender, EventArgs e)
{
string title = textBox1.Text;
if (string.IsNullOrWhiteSpace(title))
{
MessageBox.Show("A title is required!");
return;
}
Random random = new Random();
double a = random.NextDouble();
int b = random.Next();
Add(a, b, title);
textBox1.Text = string.Empty;
}
}
Like this, you have the selected item always at hand, you can request the values from the properties of the selected, and you don't have to worry about syncing the ComboBox with the items currently visible

From the documentation:
Although the ComboBox is typically used to display text items, you can add any object to the ComboBox. Typically, the representation of an object in the ComboBox is the string returned by that object's ToString method. If you want to have a member of the object displayed instead, choose the member that will be displayed by setting the DisplayMember property to the name of the appropriate member. You can also choose a member of the object that will represent the value returned by the object by setting the ValueMember property. For more information, see ListControl.
So you can just add objects that hold all the information, directly to the Items collection of the ComboBox. Later, retrieve the SelectedItem property and cast it back to the correct type.

Related

How to update the target cell of a CurrentRow in DataGridView in C#?

In my Windows Form Application, the DataGridView is updated from the TextChanged_Event of a textbox (bar code reading functionality). Every new row has values like Product Name, Quantity, Unit Price, and Total Amount. The Product Name and Unit Price values are coming from the database while I have set a default value of 1 for the Quantity. The value of Total Amount is the multiplication of Quantity and Unit Price.
Everything works fine until now and I am able to use the default 1 value for the sale Quantity of each item. However, if I want to sell an item more than once, then I need to replace this default quantity value with a custom value.
To simplify this process, I have used a Child Form with a single textbox and a button that will allow my user to put a custom value for the Quantity column which should replace the default 1 value of Quantity column.
I have tried different approaches with no luck. Because I am showing the Child Form at that part of the Sale process where the application has to look for a duplicate product in the DataGridView. If an item is already present in the DataGridView, the application asks for adding it again and when the user clicks on the Yes Button, the Child Form is shown.
So it makes my logic meaningless because after showing and making do with the custom Quantity value textbox on the Child Form, I can't access the variable on parent form for replacing its default 1 value with this custom quantity.
My code is working fine but I just need some improvement in the logic so that I can easily replace the default Quantity value with the custom value from the Child Form.
Here is my code:
public void FillCurrentSoldItemGrid(string barCode)
{
string columnList = "ProductName, UnitPrice";
DataRow dr = NewSale.SelectByItemCode(columnList, barCode);
if (dr == null)
{
//show error message
return;
}
// check duplicate value in DataGridView
string productName = dr[0].ToString();
if (dgvSoldItems.RowCount > 0)
{
foreach (DataGridViewRow dgvRow in dgvSoldItems.Rows)
{
if (dgvRow.Cells[0].Value.ToString().CompareTo(productName) == 0)
{
if (DataAccess.AskUser("This item is already present in the grid?", "Confirm Item Quantity Update") == true)
{
//my child form code
using (var customSaleQuantity = new frmCustomSaleQuantity())
{
var result = customSaleQuantity.ShowDialog();
if (result == DialogResult.OK)
{
//need to assign this value of the customQuantity string to int quantity which is holding a default 1 value)
string customQuantity = customSaleQuantity.GetCustomQuantity;
}
}
}
}
}
}
//value of string customQuantity to be assigned to int quantity.
int quantity = 1;
int unitPrice = Convert.ToInt32(dr[1]);
DataGridViewRow row = new DataGridViewRow();
row.CreateCells(dgvAllSoldItems);
row.Cells[0].Value = productName;
row.Cells[1].Value = quantity;
row.Cells[2].Value = unitPrice;
row.Cells[3].Value = (quantity * unitPrice);
dgvAllSoldItems.Rows.Add(row);
}
And here is the code from my Child Form:
public string GetCustomQuantity
{
get;
set;
}
private void btnProceedWithNewItemQuantity_Click(object sender, EventArgs e)
{
this.GetCustomQuantity = txtChooseSaleQuantity.Text.Trim();
this.Close();
}
I am new to c# and I don't have any idea of how to replace the default 1 value of quantity with the custom value if a duplicate item is detected. This is really important task and my deadline is almost over.
Any help will highly be appreciated.
there are many ways to improve logic; however, one way is to apply Object Oriented Programming (OOP) concept.
Define a static class to hold global variables, fields and functions.
Once a user enters data in the child form, pass that information to the static class getter/setter methods. Also, in your static class you can define a public function to process data.
Do not forget to refresh GridView to view the updated information.
The main reason I recommend using a static class that you can call public attributes, methods from anywhere in your application and you would not need to create a instance of class object.
static class Globals
{
// global int
public static int counter;
// global function
public static string HelloWorld()
{
return "Hello World";
}
}
Globals.counter = 10;
int localcounter = Globals.counter;
string somestring = Globals.HelloWorld();
Globals.counter2 = 30;
int localcounter2 = Globals.counter2;

How to set SelectedItem in WinForms ComboBox depending on a condition

I have a WinForms application with ComboBox in it. I want to programatically select an item depending on its value.
I tried using IndexOf but it requires the whole object, I want to do it only by value. Items are ObjectCollection and I can't use Linq on it (or don't know how).
In one place I'm setting its source like that:
private void SetItems()
{
var items = new List<ComboItem>(3);
//Add items to the list
combo.BeginUpdate();
combo.DataSource = items;
combo.ValueMember = "Value";
combo.DisplayMember = "Name";
combo.EndUpdate();
}
private class ComboItem
{
public int Value { get; set; }
public string Name { get; set; }
}
Then (in other place) I want to set selected item depending on the value. E. g. if I had the combo values:
"Option1": 2,
"Option2": 5,
"Option3": 10
I would like to do something like:
combo.Items.SelectedValue = 5
And have in combo selected Option2. Is it even possible?
1) When setting up DataSource and ValueMember for a ComboBox, to select specific value, use SelectedValue property.
Example - Assign SelectedValue
comboBox1.SelectedValue = 5;
2) When all the item of ComboBox are of type of T, you can searching between items using ComboBox.Items.Cast<T>() assign it to SelectedItem.
Example - Search using ComboBox.Items
Since all items of your ComboBox are of type of T, you can use linq Cast<T> to cast ObjectCollection to IEnumerable<T>. For example:
comboBox1.SelectedItem = comboBox1.Items.Cast<ComboItem>()
.Where(x => x.Value == 5).FirstOrDefault();
Remember to add using System.Linq;.

C# Windows Form - How do I assign a double value to a combo box string to then be displayed in a text box?

I've been having the trouble of finding a solution to my coding problem of assigning a double value to a combo box item which then that double value is displayed and added to a text box.
For instance, the beverages combo box contains: soda, tea, coffee, milk, juice, etc. So for "soda" I would like to give it the value of $1.95 which is then displayed in a "Subtotal:" text box. So then for every time a item is selected in the combo box, say soda, juice, and coffee, every time a item is selected it would add to the previous subtotal value in the text box.
Sorry if it isn't too clear but any help would be great, I've blanked out and been trying to come up with a solution for a while now and just been struggling. Thank you!
This would be a perfect use of a custom type. In this case you could create a Drink class with a Description property and a Price property. Override the .ToString() method to display only the Description.
class Drink
{
public string Description { get; set; }
public decimal Price { get; set; }
public override string ToString()
{
return Description;
}
}
From that you would instantiate a new Drink, populate the Description and the Price and add that object to your combobox. Your combobox would display "Soda" but the object also holds 1.95 in its Price property.
private void Form1_Load(object sender, EventArgs e)
{
//for demonstration purposes, we're creating 3 Drink
//objects and adding them to the combobox. Normally
//you would loop through a data source of some sort
//and populate your combobox with the newly intantiated objects.
Drink item;
item = new Drink();
item.Description = "Soda";
item.Price = 1.80M;
comboBox1.Items.Add(item);
item = new Drink();
item.Description = "Coffee";
item.Price = .95M;
comboBox1.Items.Add(item);
item = new Drink();
item.Description = "Tea";
item.Price = .65M;
comboBox1.Items.Add(item);
}
Since the combobox is holding an object, you would need to cast the selecteditem back to a Drink so that you have access to the price from the selection.
private void button1_Click(object sender, EventArgs e)
{
decimal itemPrice;
//if the textbox is empty or cannot be parsed to a decimal
//then we cast the combobox1.SelectedItem to a Drink type
//place that value into the textbox. If, however, it can be
//parsed to a decimal then we grab that value and add the
//price of our newly selected combobox item to the price
//that is currently in the textbox.
if(decimal.TryParse(textBox1.Text, out itemPrice))
{
textBox1.Text = (itemPrice + ((Drink)(comboBox1.SelectedItem)).Price).ToString();
}
else
{
textBox1.Text = (((Drink)(comboBox1.SelectedItem)).Price).ToString();
}
}
If I understand your question correctly (please provide what you have already tried next time, it makes it easier for us to help.) you can use a dictionary to map your beverages to a price.
var priceMapping = new Dictionary<string, double>()
{
{ "Soda", 1.75 },
{ "Tea", 2.00 },
{ "Coffee", 1.50 }
//etc...
};
And then, on the selected index changed event for the combobox, you can do something like this:
ComboBox comboBox = sender as ComboBox;
if (comboBox != null && comboBox.SelectedItem != null)
{
//For simplicity sake, I left error handling
//You'll want to use double.TryParse to handle any unexpected text in the subtotal textbox.
double price = Convert.ToDouble(subTotalTb.Text) + priceMapping[comboBox.SelectedItem.ToString()];
subTotalTb.Text = price.ToString();
}

How to store the actual underlying DB value in a combobox while displaying a more user-friendly value?

I need to display values like "Surreptitiously" and "Discreetly" in a comboBox but thereafter be able to set the comboboxes' SelectedItem based on the underlying DB values for those words (e.g., "S" and "D").
I reckon I can use the comboBoxes' DisplayMember and ValueMember properties for this somehow, but can I subsequently do something analagous to the following with the actual (valuemember) values:
comboBoxAdverbs.SelectedIndex = comboBoxAdverbs.Items.IndexOf(weirdAdverbs[CURRENT_ADVERB]);
As "weirdAdverbs[CURRENT_ADVERB]" contains the values like "S" and "D" it, of course, doesn't find and set the SelectedIndex when the comboBox contains the values "Surreptitiously" and "Discreetly"
If I set the combobox Item Tag value to "S" and "D" (assuming that's possible), I can loop through those values, but I'm hoping there's a one-line way of doing it similar to the "IndexOf()" above.
I use a template class for this and it comes in pretty darn handy. The combo box will show whatever text you want and you can store a value with it.
public class cboItem<T>
{
public cboItem(string name, T value)
{
this.Name = name;
this.Value = value;
}
public string Name { get; set; }
public T Value { get; set; }
public override string ToString()
{
return Name == null ? "" : Name;
}
}
Combo box items can be anything, including classes/structs. By default it will use the ToString() implementation to display items, but if you populate a set of objects you can use DisplayMember and ValueMember to great effect.
As a simple example to give you some ideas we'll bind the combo box to a set of KeyValuePair instances for your weird verb codes and their descriptive names. Alternatively you can use linq to compose anonymous types, or create your own suitable classes/structs.
private void populateCombo()
{
comboBoxAdverbs.Items.Clear();
comboBoxAdverbs.Items.Add( new Tuple<string, string>( "S", "Surreptitiously" ) );
comboBoxAdverbs.Items.Add( new Tuple<string, string>( "D", "Discreetly" ) );
comboBoxAdverbs.DisplayMember = "Item2";
}
Then in your code where you want to select an item matching a provided code: (I.e. "D")
var item = comboBoxAdverbs.Items
.OfType<Tuple<string,string>>()
.FirstOrDefault(i => string.Compare(i.Item1, textBox1.Text, true) == 0);
if (item != null)
comboBoxAdverbs.SelectedItem = item;
This attempts to find the matching item by comparing the key against whatever input (in this case a textbox value) and if it finds a match, sets the SelectedItem to tell the combo box to select it.
** Edit: Whups, had originally use KeyValuePair which I didn't realize was a struct so no Null check-ability. Changed to Tuple (Essentially Pair)
What I found that works for me is to store the selectedindex value, after it's set, into the combobox's Tag property. Then, if the user attempts to change the selectedIndex when it is supposed to be in a "readonly" state, simply change it back to the selectedIndex value stored in the Tag property:
comboBoxPlatypusId.SelectedIndex = comboBoxPlatypusId.Items.IndexOf(DuckbillVals[Duckbill_PlatypusID]);
comboBoxPlatypusId.Tag = comboBoxPlatypusId.SelectedIndex;
...
private void comboBoxFunnyMammals_SelectedValueChanged(object sender, EventArgs e) {
var cb = sender as ComboBox;
if (cb != null)
{
int validSelection = Convert.ToInt32(cb.Tag);
if (cb.SelectedIndex != validSelection) {
cb.SelectedIndex = validSelection;
}
}
}

Binding a textbox to a datagridviewtextboxcolumn?

Is it possible, to bind (or similar) a standard textbox to display the contents (dynamically) of the selected cell within a datagridview textboxcolumn?
My goal is that when a cell within this column has it's value altered, the textbox.text is also changed, and when the user selects a cell then types something in this separate textbox the value is updating the datagridview textboxcolumns value on the fly.
Yes you may bind common dataSource to both TextBox and DataGridView.
public class Foo
{
public string Item { get; set; }
}
private void Form2_Load(object sender, EventArgs e)
{
List<Foo> list = new List<Foo>()
{
new Foo() { Item="1" },
new Foo() { Item="2" }
};
dataGridView1.DataSource = list;
textBox1.DataBindings.Add("Text", list, "Item");
}
Applying the idea from "adatapost" to a DataGridView in C#:
TextBox txt = this.txtBox1;
DataGridView dgv = this.datagridview1;
txt.DataBindings.Add("Text", dgv.DataSource, "FieldName");
dgv = null;
txt = null;
It might not be necessary to declare separate variables to hold your TextBox and DataGridView while you create the Binding. I just show these for clarity, in fact, this would be sufficient:
this.txtBox1.DataBindings.Add("Text", this.datagridview1.DataSource, "FieldName"
To clarify, "Text" means output the value back to the "Text" property of the TextBox, and "FieldName" should be replaced with whatever the column is in your DataGridView that you want to bind to.
Note - make sure that you have already set the DataSource / populated the DataGridView before you put the Binding code, if the DataSource is not set and therefore containing the field that you wish to bind to you will get an error.

Categories

Resources