I want fill a combobox with a matrix
Matrix:
object[,] codes = new object[,] {
{ "1", "BANK S/A" },
{ "2", "BANK Center" },
{ "3", "BANK AMAZON S/A" }};
Fill my combobox:
comboBank.DataSource = codes;
comboBanco.DataBind();
but in my combobox appears the items
1
BANK S/A
2
Bank Center
3
Bank Amazon S/A
I want fill this combobox with just the names, not the ID's, and in the Value propertie of these combobox, I want the ID.
What I Want in my combobox
Bank S/A
Bank Center
Bank Amazon S/A
How can I do that ?
Here's a simple helper method you can use to get one column out of a two dimensional array:
public static IEnumerable<T> GetColumn<T>(T[,] array, int column)
{
for (int i = 0; i < array.GetLength(0); i++)
yield return array[i, column];
}
Using that you can just modify your code to:
comboBank.DataSource = codes.GetColumn(1);
Having said that, the real issue here is that you're using a multi-dimensional array when what you really should have is a single dimensional array of some object that contains both an int and a string.
public class Code
{
public int ID { get; set; }
public string Name { get; set; }
}
Code[] codes = new Code[]{
new Code(){ID=1, Name="BANK S/A"},
new Code(){ID=2, Name="BANK Center"},
new Code(){ID=3, Name="BANK AMAZON S/A"},
};
Once you have that strongly typed array you can either use Select to select the property to show, or set the DisplayMember of the combo box.
Maybe you could try something like this:
List<dynamic> list = new List<dynamic>();
for(int i = 0; i < codes.Lenght; i++)
list.Add(new { Value = code[i][0], Text = code[i][1] });
comboBox.DataSource = list;
comboBox.DisplayMember = "Text";
comboBox.ValueMember = "Value";
Related
I have an array:
decimal[,] SmoothieListDecimal = { {5.99M, 6.99M, 7.99M, 8.99M},
{6.99M, 7.99M, 8.99M, 9.99M} }
And I have two combo boxes:
cmbSize and cmbStyle
cmbSize has: Small, Medium, Large, and King, which make up the values in the array.
The second combo box is cmbStyle, which includes only two selections, "Regular" and "Organic". The "Organic" prices are $1.00 more expensive and derived from the second row.
So, for example, if a user selects a "Medium" size and "Regular" style, the price would be pulled from row 1, column 1 in the array.
My question is, how do I set my variables to their respective array coordinates, and furthermore, how would I code the equation to handle this price selection?
I am using (Visual Studio 2015 and C#)
Thanks!
How about creating a class containing informations about smoothie prices:
public class SmoothiePrices
{
public string Description { get; set; }
public Dictionary<string, double> SizeAndPrice { get; set; }
}
Fill this with your info:
private List<SmoothiePrices> prices = new List<SmoothiePrices>();
public void InitSmoothies
{
prices.Add(new SmoothiePrices()
{
Name = "Regular",
SizeAndPrice = new Dictionary<string, double>()
{
{"Small", 5.99},
{"Normal", 6.99}
// And so on
};
});
}
Now you have created a data structure and can fill the combos:
private void InitStyleCombo()
{
this.cmbStyle.DisplayMember = "Description";
this.cmbStyle.DataSource = this.prices;
}
The last thing to do is to fill the cmbSize depending on the selection of the cmbStyle combo.
private void cmbStyle_SelectedIndexChanged(object sender, EventArgs e)
{
var smoothiePrice = this.cmbStyle.SelectedValue as SmoothiePrice;
this.cmbSize.DisplayMember = "Key";
this.cmbSize.ValueMember = "Value";
this.cmbSize.DataSource = smoothiePrice.SizeAndPrice;
}
To access the selected price for the size use:
var selectedPrice = (double)this.cmbSize.SelectedValue;
There are a lot of ways to do this, but one easy way (but certainly not the best or most robust) is to load the ComboBox.Items in the correct order for SmoothieListDecimal.
decimal price;
int column = cmbSize.SelectedIndex; // 0=Small,1=Medium,2=Large,3=King
int row = cmbStyle.SelectedIndex; // 0=Regular,1=Organic
if (column < 0)
MessageBox("Please select a size");
else if (row < 0)
MessageBox("Please select a style");
else
price = SmoothieListDecimal[row, col];
I am trying to populate a combobox from 2D array. I want it the first dimension to be assigned as DisplayMember values, and the second as ValueMemeber. Have been looking online, but I could not find a solution that would work for me. Below is the code that I am trying to use. This does not work.
string[,] Options = new string[3, 2]{
{"Invoice", "3"},
{"Group Invoice", "4"},
{"Group Invoice BUCKS", "5"} };
cboOption.DataSource = Options;
I have tried using a for loop and it does not work either and I get this error message: "Items collection cannot be modified when the DataSource property is set." Example below:
string[,] Options = new string[3, 2]{
{"Invoice", "3"},
{"Group Invoice", "4"},
{"Group Invoice BUCKS", "5"} };
cboOption.DisplayMember = "Text";
cboOption.ValueMember = "Key";
for (int i = 0; i < Options.GetLength(0); i++)
{
cboOption.Items.Add(new { Text = Options[i, 0], Key=Convert.ToInt16(Options[i, 1]) });
}
Can I do that? If I can could you give me an example.
Thank you
Are you sure you have tried this?.. this is a paste straight from vs and it's working
private void button1_Click(object sender, EventArgs e)
{
string[,] Options = new string[3, 2]{
{"Invoice", "3"},
{"Group Invoice", "4"},
{"Group Invoice BUCKS", "5"} };
for (int i = 0; i < Options.GetLength(0); i++)
{
cboOption.Items.Add(new { Text = Options[i, 0], Key = Convert.ToInt16(Options[i, 1]) });
}
cboOption.DisplayMember = "Text";
cboOption.ValueMember = "Key";
}
When you have a control databound, you do not add items to the control, you add them to the bound datasource. Instead of adding items to cboOption.Items, add them to the collection that your control is bound to. In your case however, you have an array. You would be better off rewriting that array into a resizable collection or datatable.
Thanks to #gmiley for the advise. After trying all the different options came up with a solution.
So I created a class Options instead of the array
public class Options
{
public string Name { get; set; }
public int Value { get; set; }
}
Then I used the code below to populate combobox
var items = new List<Options>
{
new Options() { Name="Invoice", Value=3},
new Options() { Name="Group Invoice", Value=4},
new Options() { Name="Group Invoice BUCKS", Value=5},
};
cboOption.DataSource = items;
cboOption.DisplayMember = "Name";
cboOption.ValueMember = "Value";
I have a CSV that is delivered to my application from various sources. The CSV will always have the same number columns and the header values for the columns will always be the same.
However, the columns may not always be in the same order.
Day 1 CSV may look like this
ID,FirstName,LastName,Email
1,Johh,Lennon,jlennon#applerecords.com
2,Paul,McCartney,macca#applerecords.com
Day 2 CSV may look like this
Email,FirstName,ID,LastName
resident1#friarpark.com,George,3,Harrison
ringo#allstarrband.com,Ringo,4,Starr
I want to read in the header row for each file and have a simple mechanism for associating each "column" of data with the associated property I have defined in my class.
I know I can use selection statements to figure it out, but that seems like a "bad" way to handle it.
Is there a simple way to map "columns" to properties using a dictionary or class at runtime?
Use a Dictionary to map column heading text to column position.
Hard-code mapping of column heading text to object property.
Example:
// Parse first line of text to add column heading strings and positions to your dictionary
...
// Parse data row into an array, indexed by column position
...
// Assign data to object properties
x.ID = row[myDictionary["ID"]];
x.FirstName = row[myDictionary["FirstName"]];
...
You dont need a design pattern for this purpose.
http://www.codeproject.com/Articles/9258/A-Fast-CSV-Reader
I have used this Reader, while it is pretty good, it has a functionality as row["firstname"] or row["id"] which you can parse and create your objects.
I have parsed both CSV files using Microsoft.VisualBasic.FileIO.TextFieldParser. I have populated DataTable after parsing both csv files:
DataTable dt;
private void button1_Click(object sender, EventArgs e)
{
dt = new DataTable();
ParseCSVFile("day1.csv");
ParseCSVFile("day2.csv");
dataGridView1.DataSource = dt;
}
private void ParseCSVFile(string sFileName)
{
var dIndex = new Dictionary<string, int>();
using (TextFieldParser csvReader = new TextFieldParser(sFileName))
{
csvReader.Delimiters = new string[] { "," };
var colFields = csvReader.ReadFields();
for (int i = 0; i < colFields.Length; i++)
{
string sColField = colFields[i];
if (sColField != string.Empty)
{
dIndex.Add(sColField, i);
if (!dt.Columns.Contains(sColField))
dt.Columns.Add(sColField);
}
}
while (!csvReader.EndOfData)
{
string[] fieldData = csvReader.ReadFields();
if (fieldData.Length > 0)
{
DataRow dr = dt.NewRow();
foreach (var kvp in dIndex)
{
int iVal = kvp.Value;
if (iVal < fieldData.Length)
dr[kvp.Key] = fieldData[iVal];
}
dt.Rows.Add(dr);
}
}
}
}
day1.csv and day2.csv as mentioned in the question.
Here is how output dataGridView1 look like:
Here is a simple generic method that will take a CSV file (broken into string[]) and create from it a list of objects. The assumption is that the object properties will have the same name as the headers. If this is not the case you might look into the DataMemberAttribute property and modify accordingly.
private static List<T> ProcessCSVFile<T>(string[] lines)
{
List<T> list = new List<T>();
Type type = typeof(T);
string[] headerArray = lines[0].Split(new char[] { ',' });
PropertyInfo[] properties = new PropertyInfo[headerArray.Length];
for (int prop = 0; prop < properties.Length; prop++)
{
properties[prop] = type.GetProperty(headerArray[prop]);
}
for (int count = 1; count < lines.Length; count++)
{
string[] valueArray = lines[count].Split(new char[] { ',' });
T t = Activator.CreateInstance<T>();
list.Add(t);
for (int value = 0; value < valueArray.Length; value++)
{
properties[value].SetValue(t, valueArray[value], null);
}
}
return list;
}
Now, in order to use it just pass your file formatted as an array of strings. Let's say the class you want to read into looks like this:
class Music
{
public string ID { get; set; }
public string FirstName { get; set; }
public string LastName { get; set; }
public string Email { get; set; }
}
So you can call this:
List<Music> newlist = ProcessCSVFile<Music>(list.ToArray());
...and everything gets done with one call.
I am into day 5 of learning c#, and am trying to figure out how to fill/re-fill a ListView control, containing 10 rows and 12 columns, using a foreach loop. I have coded the functionality I'm after in C.
void listPopulate(int *listValues[], int numberOfColumns, int numberOfRows)
{
char table[100][50];
for (int columnNumber = 0; columnNumber < numberOfColumns; ++columnNumber)
{
for (int rowNumber = 0; rowNumber < numberOfRows; ++rowNumber)
{
sprintf(&table[columnNumber][rowNumber], "%d", listValues[columnNumber][rowNumber]);
// ...
}
}
}
Here is what I have figured out so far:
public void listView1_Populate()
{
ListViewItem item1 = new ListViewItem("value1");
item1.SubItems.Add("value1a");
item1.SubItems.Add("value1b");
ListViewItem item2 = new ListViewItem("value2");
item2.SubItems.Add("value2a");
item2.SubItems.Add("value2b");
ListViewItem item3 = new ListViewItem("value3");
item3.SubItems.Add("value3a");
item3.SubItems.Add("value3b");
....
listView1.Items.AddRange(new ListViewItem[] { item1, item2, item3 });
}
I'm assuming that I would have to do the creation of the list items in a separate step. So my question is: there must be a way to do this in C# with a for or foreach loop, no?
I am not sure if I understood you correctly, but here's i think what you need...
Actually it depends on your DataSource which you are using to fill up the ListView.
Something like this (I am using Dictioanry as a DataSource here) -
// Dictinary DataSource containing data to be filled in the ListView
Dictionary<string, List<string>> Values = new Dictionary<string, List<string>>()
{
{ "val1", new List<string>(){ "val1a", "val1b" } },
{ "val2", new List<string>(){ "val2a", "val2b" } },
{ "val3", new List<string>(){ "val3a", "val3b" } }
};
// ListView to be filled with the Data
ListView listView = new ListView();
// Iterate through Dictionary and fill up the ListView
foreach (string key in Values.Keys)
{
// Fill item
ListViewItem item = new ListViewItem(key);
// Fill Sub Items
List<string> list = Values[key];
item.SubItems.AddRange(list.ToArray<string>());
// Add to the ListView
listView.Items.Add(item);
}
I have simplified the code for your understanding, since there several ways to iterate through a Dictionary...
Hope it helps!!
You do this almost exactly the same as in C. Just loop through the collection...
int i = 0;
foreach (var column in listValues)
{
var item = new ListViewItem("column " + i++);
foreach (var row in column)
{
item.SubItems.Add(row);
}
listView1.Items.Add(item);
}
It's hard to provide a real example without seeing what your collection looks like, but for an array of arrays this will work.
I have a simple model
public class OneModel
{
public string Email { get; set; }
public string Name { get; set; }
}
And I created a simple list (OneModel datatype):
List<OneModel> someLists = new List<OneModel>{
new OneModel{Name="A 1", Email="a1#some.com"},
new OneModel{Name="A 2", Email="a2#some.com"},
new OneModel{Name="A 3", Email="a3#some.com"},
new OneModel{Name="B 1", Email="b1#some.com"},
new OneModel{Name="C 1", Email="c1#some.com"},
}
I want to create another list with random concatenated Name from first list, like as:
List<string> ... {"A 1-A 3", "A 2-C 1",...} or something like that.
How to do that ?
Assuming .NET Framework 4.0:
var random = new Random();
var result = new List<string>();
var count = random.Next(10, 20); // How many results do you want, really!?
for (int i = 0; i < count; ++i) {
var query = from item in someLists
order by random.Next()
select item.Name;
var items = query.Take(2); // I assume you want two "names" in each item
result.Add(string.Join("-", items));
}
Examine result for your random-length list of random randomness...
But what do you need it for...?