2D array to populate combobox - c#

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";

Related

How to list all the rows of a Gtk.Treeview

I'm having trouble grasping the use of GTK's TreeView and so I am running through some examples I have found online. Putting them together I am unable to work out how to extract the information in the view. I am operating the TreeView as a simple List with columns for the presentation of tabled data.
I am getting confused between the roles of models, stores and the actual treeview itself.
I am working from the example here
using System;
using System.Collections;
using Gtk;
public class Actress
{
public string Name;
public string Place;
public int Year;
public Actress(string name, string place, int year)
{
Name = name;
Place = place;
Year = year;
}
}
public class SharpApp : Window
{
ListStore store;
Statusbar statusbar;
enum Column
{
Name,
Place,
Year
}
Actress[] actresses =
{
new Actress("Jessica Alba", "Pomona", 1981),
new Actress("Sigourney Weaver", "New York", 1949),
new Actress("Angelina Jolie", "Los Angeles", 1975),
new Actress("Natalie Portman", "Jerusalem", 1981),
new Actress("Rachel Weissz", "London", 1971),
new Actress("Scarlett Johansson", "New York", 1984)
};
public SharpApp() : base ("ListView")
{
BorderWidth = 8;
SetDefaultSize(350, 250);
SetPosition(WindowPosition.Center);
DeleteEvent += delegate { Application.Quit(); };
VBox vbox = new VBox(false, 8);
ScrolledWindow sw = new ScrolledWindow();
sw.ShadowType = ShadowType.EtchedIn;
sw.SetPolicy(PolicyType.Automatic, PolicyType.Automatic);
vbox.PackStart(sw, true, true, 0);
store = CreateModel();
TreeView treeView = new TreeView(store);
treeView.RulesHint = true;
treeView.RowActivated += OnRowActivated;
sw.Add(treeView);
AddColumns(treeView);
statusbar = new Statusbar();
vbox.PackStart(statusbar, false, false, 0);
Add(vbox);
ShowAll();
}
void OnRowActivated (object sender, RowActivatedArgs args) {
TreeIter iter;
TreeView view = (TreeView) sender;
if (view.Model.GetIter(out iter, args.Path)) {
string row = (string) view.Model.GetValue(iter, (int) Column.Name );
row += ", " + (string) view.Model.GetValue(iter, (int) Column.Place );
row += ", " + view.Model.GetValue(iter, (int) Column.Year );
statusbar.Push(0, row);
}
// *** if I can dump treeview to the console here I'll be happy ***
// *** I'd prefer a foreach or do/while ***
}
void AddColumns(TreeView treeView)
{
CellRendererText rendererText = new CellRendererText();
TreeViewColumn column = new TreeViewColumn("Name", rendererText,
"text", Column.Name);
column.SortColumnId = (int) Column.Name;
treeView.AppendColumn(column);
rendererText = new CellRendererText();
column = new TreeViewColumn("Place", rendererText,
"text", Column.Place);
column.SortColumnId = (int) Column.Place;
treeView.AppendColumn(column);
rendererText = new CellRendererText();
column = new TreeViewColumn("Year", rendererText,
"text", Column.Year);
column.SortColumnId = (int) Column.Year;
treeView.AppendColumn(column);
}
ListStore CreateModel()
{
ListStore store = new ListStore( typeof(string),
typeof(string), typeof(int) );
foreach (Actress act in actresses) {
store.AppendValues(act.Name, act.Place, act.Year );
}
return store;
}
public static void Main()
{
Application.Init();
new SharpApp();
Application.Run();
}
}
An array of actresses is created at the top of the code, and that is used to populate a ListStore (towards the end of the code) that is in turn used to populate the TreeView.
I want to iterate over the treeview's data and update the columns within it.
To this end, since OnRowActivated is a nice place to dump information, I'd like to dump out the entire treeview contents to the console when a node is selected.
Any help in guiding me to get this done (and hopefully understanding it in the process) would be appreciated.
Whilst certainly not elegant I found the answer which also updates some of the data in the model. I'd be happy if anyone could improve upon this.
TreeIter iter;
TreeModel model = tv.Model;
if (model.GetIterFirst(out iter))
{
do
{
newYear = ModifyYear((string)model.GetValue(iter, (int)Column.Year));
Console.WriteLine("Updating: {0} -- {1} {2}",
(string)model.GetValue(iter, (int)Column.Name),
model.GetValue(iter, (int)Column.Year),
newYear );
model.SetValue(iter, (int)Column.Year, (int)newYear);
} while (model.IterNext(ref iter));
}

Fill combobox with a matrix

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";

Assigning a button tag based on random items from an array

{
var buttonnameString = new List<string> { "button1", ... , "button12" };
for(int i = 0; i < 12; i++)
{
// Random car assignment to button
Random myRandom = new Random();
var carString = new List<string> { "Camaro", ... , "Model T" };
int index = myRandom.Next(carString.Count);
var name = carString[index];
carString.RemoveAt(index);
Tag = name.ToString();
}
}
In advance, thank you for any help that is provided. I'm a first year C# student so I know I have a lot to learn, but I've exhausted the extent of my google skills on trying to get this to work.
What I'm trying to do, is make a matching program. This program will have 12 buttons, labeled "button1", "button2"....etc. When the button is clicked, it will display it's tag, which is provided from a random array. I've gotten the random feature to work on assigning only a single buttons tag. Where I'm hung up at, is repeating this to all the buttons in a groupbox. I've tried the foreach venue, but couldn't get it to work successfully. Eventually I tried other methods as well. Below is where I've stopped at as I'm unsure on where to go. The two major questions that I have are
How do I assign the random string to a wildcard button tag?
What is the best way to accomplish randomly assigning 12 car names, to 12 buttons? The use of two arrays?
Try this:
{
var numOfButtons = 12;
var matchingButtonIndex = 0;
// Random car assignment to button
Random myRandom = new Random();
var buttons = new List<Button> { button1, ... , button12 };
var carString = new List<string> { "Camaro", ... , "Model T" };
while (matchingButtonIndex < numOfButtons)
{
int index = myRandom.Next(carString.Count);
var name = carString[index];
if (name != null)
{
buttons[matchingButtonIndex].Tag = name;
carString[index] = null;
matchingButtonIndex = matchingButtonIndex + 1;
}
}
}
Notice I have changed the button names array to an array of buttons. I have also emptied out the carString as I find unused car names.
Iterating over buttons is easy when you iterate through the form's Controls
var carString = new List<string> { "Camaro", "Mini Cooper", "Porsche 944", "Ford Focus", "Chevy Blazer", "Model T", "Camaro", "Mini Cooper", "Porsche 944", "Ford Focus", "Chevy Blazer", "Model T" };
foreach(Control c in Controls)
{
if (c is Button)
{
Random myRandom = new Random();
int index = myRandom.Next(carString.Count);
c.Tag = carString[index];
}
}

adding items to columns/rows in listview using foreach

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.

Binding a generic List<string> to a ComboBox

I have a ComboBox and I want to bind a generic List to it. Can anyone see why the code below won't work? The binding source has data in it, but it won't fill the ComboBox data source.
FillCbxProject(DownloadData Down)
{
BindingSource bindingSource = new BindingSource();
bindingSource.DataSource = Down.ProjectList;
cbxProjectd.DataSource = bindingSource;
}
On a side note: Is it bad to pass around an instance of a class?
Thanks!
You need to call the Bind method:
cbxProjectd.DataBind();
If this is for winforms then you need to make sure what you have is being called, the following works:
BindingSource bs = new BindingSource();
bs.DataSource = new List<string> { "test1", "test2" };
comboBox1.DataSource = bs;
Although you can set the ComboBox's DataSource directly with the list.
this is the simple way (it works correctly):
List<string> my_list = new List<string>();
my_list.Add("item 1");
my_list.Add("item 2");
my_list.Add("item 3");
my_list.Add("item 4");
my_list.Add("item 5");
comboBox1.DataSource = my_list;
Here is a rather simple way that doesn't use BindingSource:
first, add the generic list of string, perhaps to a "consts/utils" class:
public static List<string> Months = new List<string>
{
"Jan",
"Feb",
"Mar",
"Apr",
"May",
"Jun",
"Jul",
"Aug",
"Sep",
"Oct",
"Nov",
"Dec"
};
And here's how you add those strings to a combo box:
comboBoxMonth.Items.AddRange(UsageRptConstsAndUtils.Months.ToArray<object>());
BindingSource bs = new BindingSource();
bs.DataSource = getprojectname();
comboBox1 = new ComboBox();
comboBox1.DataSource = bs;
Using Yuriy Faktorovich's code above as a basis, here is how to get a list of dates in LongDateString format for a given number of weeks, and assign them to a combo box. This uses "Monday" but you can simply replace "Monday" with any other DOW to suit your purposes:
private void PopulateSchedulableWeeks()
{
int WEEKS_COUNT = 13;
List<String> schedulableWeeks = PlatypusUtils.GetWeekBeginnings(WEEKS_COUNT).ToList();
BindingSource bs = new BindingSource();
bs.DataSource = schedulableWeeks;
comboBoxWeekToSchedule.DataSource = bs;
}
public static List<String> GetWeekBeginnings(int countOfWeeks)
{
// from http://stackoverflow.com/questions/6346119/datetime-get-next-tuesday
DateTime today = DateTime.Today;
// The (... + 7) % 7 ensures we end up with a value in the range [0, 6]
int daysUntilMonday = ((int)DayOfWeek.Monday - (int)today.DayOfWeek + 7) % 7;
DateTime nextMonday = today.AddDays(daysUntilMonday);
List<String> mondays = new List<string>();
mondays.Add(nextMonday.ToLongDateString());
for (int i = 0; i < countOfWeeks; i++)
{
nextMonday = nextMonday.AddDays(7);
mondays.Add(nextMonday.ToLongDateString());
}
return mondays;
}
...and, if you want to add the actual date to the combo box, too, you can use a Dictionary like so:
int WEEKS_TO_OFFER_COUNT = 13;
BindingSource bs = new BindingSource();
Dictionary<String, DateTime> schedulableWeeks = AYttFMConstsAndUtils.GetWeekBeginningsDict(WEEKS_TO_OFFER_COUNT); bs.DataSource = schedulableWeeks;
comboBoxWeekToSchedule.DataSource = bs;
comboBoxWeekToSchedule.DisplayMember = "Key";
comboBoxWeekToSchedule.ValueMember = "Value";
public static Dictionary<String, DateTime> GetWeekBeginningsDict(int countOfWeeks)
{
DateTime today = DateTime.Today;
// The (... + 7) % 7 ensures we end up with a value in the range [0, 6]
int daysUntilMonday = ((int)DayOfWeek.Monday - (int)today.DayOfWeek + 7) % 7;
DateTime nextMonday = today.AddDays(daysUntilMonday);
Dictionary<String, DateTime> mondays = new Dictionary<String, DateTime>();
mondays.Add(nextMonday.ToLongDateString(), nextMonday);
for (int i = 0; i < countOfWeeks; i++)
{
nextMonday = nextMonday.AddDays(7);
mondays.Add(nextMonday.ToLongDateString(), nextMonday);
}
return mondays;
}
If anyone finds this necro thread, make sure your list does not contain null items.
Otherwise binding will fail silently!
//This will not work!
comboBox1.DataSource = new List<string> { "test1", null, "test2" };
//This is legit!
comboBox1.DataSource = new List<string> { "test1", "", "test2" };

Categories