adding items to columns/rows in listview using foreach - c#

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.

Related

SubItems of ListView are not displayed in winforms

I am creating a winforms application in visual studio 2017, I am populating a ListView using a
List<KeyValuePair<string, string>>
Examples of the data are:
List<KeyValuePair<ABC, 123>>
List<KeyValuePair<ABC, 456>>
List<KeyValuePair<ABC, 789>>
List<KeyValuePair<DEF, 123>>
List<KeyValuePair<DEF, 233>>
I try to diplay this in a ListView, where I would like to have sometihng like this:
ABC
123
456
789
DEF
123
233
Where the ABC and the DEF are selectable only. I try to write a code to do this, but unfortunately it only displays the ABC and DEF without the subitems.
The code I wrote is:
workOrderClusters = GetItac.FilterWorkOrderClusters();
// GetItac.FilterWorkOrderClusters() is a
List<KeyValuePair<string,string>>
string current; string previous,
foreach (var workOrderCluster in workOrderClusters)
{
current = workOrderCluster.Key;
if (current != previous)
{
var listViewItem = new ListViewItem(workOrderCluster.Key);
foreach (var cluster in workOrderClusters)
{
if (cluster.Key == current)
{
listViewItem.SubItems.Add(cluster.Value);
}
}
}
previous = current;
listView1.Items.Add(listViewItem);
My question is, is there anyway to make the ListView display as expected ?
ListView shows sub items if it's in Details view and it has some columns.
Let's say you have the following data:
var list = new List<KeyValuePair<string, int>>(){
new KeyValuePair<string, int>("ABC", 123),
new KeyValuePair<string, int>("ABC", 456),
new KeyValuePair<string, int>("ABC", 789),
new KeyValuePair<string, int>("DEF", 123),
new KeyValuePair<string, int>("DEF", 233),
};
To convert your data structure to ListView items you can first group data based on the key:
var data = list.GroupBy(x => x.Key).Select(x => new
{
Key = x.Key,
Values = x.Select(a => a.Value)
});
Then add items and sub items to the control:
foreach(var d in data)
{
var item = listView1.Items.Add(d.Key);
foreach (var v in d.Values)
item.SubItems.Add(v.ToString());
}
And then setup ListView to show them:
listView1.View = View.Details;
var count = data.Max(x => x.Values.Count());
for (int i = 0; i <= count; i++)
listView1.Columns.Add($"Column {i+1}");
Note
As also mentioned in the comments, probably TreeView is more suitable to show such data. In case you want to add that data to TreeView, after grouping data you can use the following code:
foreach (var d in data)
{
var node = treeView1.Nodes.Add(d.Key);
foreach (var v in d.Values)
node.Nodes.Add(v.ToString());
}

How do i add data to a specific column in datagridview?

I have i already made 3 lists of elements that i want to insert on my datagridview,
but the problem is when i try to insert data on my datagrid a receive something like this,
so to insert data i used the following code:
IList<string> ruas = new List<string>();
foreach (var element in Gdriver.FindElements(By.ClassName("search-title")))
{
//ruas.Add(element.Text);
table.Rows.Add(element.Text);
}
IList<string> codps = new List<string>();
foreach(var Codpelement in Gdriver.FindElements(By.ClassName("cp")))
{
table.Rows.Add("",Codpelement.Text);
}
IList<string> Distritos = new List<string>();
foreach (var Distritoelement in Gdriver.FindElements(By.ClassName("local")))
{
//Distritos.Add(Distritoelement.Text);
table.Rows.Add("","",Distritoelement.Text.Substring(Distritoelement.Text.LastIndexOf(',') + 1));
}
Could you kindly, tell me a better way to make the data appear from top to bottom?
Thanks.
The problem is that you enter a single value per row. You should have three rows in total, but you have 3 * numberofcolumns rows. Instead of your current approach I recommend the following:
IList<string> ruas = new List<string>();
foreach (var element in Gdriver.FindElements(By.ClassName("search-title")))
{
ruas.Add(element.Text);
}
IList<string> codps = new List<string>();
foreach(var Codpelement in Gdriver.FindElements(By.ClassName("cp")))
{
codps.Add(Codpelement.Text);
}
IList<string> Distritos = new List<string>();
foreach (var Distritoelement in Gdriver.FindElements(By.ClassName("local")))
{
Distritos.Add(Distritoelement.Text.Substring(Distritoelement.Text.LastIndexOf(',') + 1));
}
for (int i = 0; i < ruas.Count; i++) {
table.Rows.Add(ruas.ElementAt(i), codps.ElementAt(i), Distritos.ElementAt(i));
}

custom sorting in a bindinglist of keyvaluepairs

I have a bindinglist of keyvaluepair filled dynamicaly.
BindingList<KeyValuePair<int, string>> Homelist = new BindingList<KeyValuePair<int, string>>();
foreach (ListItem item in listBox2.Items)
{
Homelist.Add(new KeyValuePair<int, string>(item.Id, item.Name));
}
The list has key(id) and value(text) as shown
I want to sort the first 5 items asc and then the rest items also asc.the sorting must be by value and not by key.
example: if I have the values : 4,5,8,7,6,10,9,3,2,1,22 the sorting result must be 4,5,6,7,8 ,1,2,3,9,10,22.Any idea?
solved answer:
public int Compare(KeyValuePair<int,string> a, KeyValuePair<int,string> b)
{
return a.Value.CompareTo(b.Value);
}
List<keyvaluepair><int,>> Playinglist = new List<keyvaluepair><int,>>();
for (int i = 0; i < 5; i ++)
{
Playinglist.Add(Homelist[i]);
}
Playinglist.Sort(Compare);
List<keyvaluepair><int,>> Benchlist = new List<keyvaluepair><int,>>();
for (int i = 5; i < Homelist.Count(); i++)
{
Benchlist.Add(Homelist[i]);
}
Benchlist.Sort(Compare);
//union 2 lists
var unionedList = new List<keyvaluepair><int,>>();
unionedList.AddRange(Playinglist.Union(Benchlist));
Homelist.Clear();
for (int i = 0; i < unionedList.Count(); i++)
{
Homelist.Insert(i, unionedList[i]);
}
game.GetHomelist = Homelist;
The idea that Tony Hopkinson said is to chop the list into two. Sort them separately and then join them back togther.After that clear the bindlist and filled from the join list. Sorting can be applied only in List<> and not to the BindLists<>.The answere is in edited question

any better way of Sorting my dropdownlist

After I retrieve the country names in English, I convert the country names to localized versions, I need to sort those names again, so I used SortDropDownList. Here, after I sort my DropDownList Items, I am losing the PrivacyOption attribute I set.
Can someone suggest solutions to sort my DropDownList while also retaining the PrivacyOption attribute?
I am using asp.net4.0 along with C# as CodeBehind:
int iCount = 1;
//fetch country names in English
List<CountryInfo> countryInfo = ReturnAllCountriesInfo();
foreach (CountryInfo c in countryInfo)
{
if (!string.IsNullOrEmpty(Convert.ToString(
LocalizationUtility.GetResourceString(c.ResourceKeyName))))
{
ListItem l = new ListItem();
l.Text = Convert.ToString(
LocalizationUtility.GetResourceString(c.ResourceKeyName));
l.Value = Convert.ToString(
LocalizationUtility.GetResourceString(c.ResourceKeyName));
//True /False*
l.Attributes.Add("PrivacyOption", *Convert.ToString(c.PrivacyOption));
drpCountryRegion.Items.Insert(iCount, l);
iCount++;
}
//sorts the dropdownlist loaded with country names localized language
SortDropDownList(ref this.drpCountryRegion);
}
And the code to SortDropDownList items:
private void SortDropDownList(ref DropDownList objDDL)
{
ArrayList textList = new ArrayList();
ArrayList valueList = new ArrayList();
foreach (ListItem li in objDDL.Items)
{
textList.Add(li.Text);
}
textList.Sort();
foreach (object item in textList)
{
string value = objDDL.Items.FindByText(item.ToString()).Value;
valueList.Add(value);
}
objDDL.Items.Clear();
for (int i = 0; i < textList.Count; i++)
{
ListItem objItem = new ListItem(textList[i].ToString(),
valueList[i].ToString());
objDDL.Items.Add(objItem);
}
}
Sort the data before you populate the DropDownList.
IEnumerable<Country> sortedCountries = countries.OrderBy(
c => LocalizationUtility.GetResourceString(c.ResourceKeyName));
foreach (Country country in sortedCountries)
{
string name = LocalizationUtility.GetResourceString(country.ResourceKeyName);
if (!string.IsNullOrEmpty(name))
{
ListItem item = new ListItem(name);
item.Attributes.Add(
"PrivacyOption",
Convert.ToString(country.PrivacyOption));
drpCountryRegion.Items.Add(item);
}
}
Have you thought about sorting the information in a SortedDictionary instead of a List?
I am not quiet sure if I understand how your implementation of SortDropDownList method works. However, I can suggest using a List<KeyValue<string, string>> to bind to your DropDownList. You can use the English part and local part in your KeyValuePair and sort accordingly.

Better way to bind generic List to DomainUpDown control (text spin control)

I have been trying to find out how to bind data to a
System.Windows.Forms.DomainUpDown() control.
Currently I have only come up with:
private void Init()
{
List<string> list = new List<string>();
list = get4000Strings(); //4000 items
foreach (string item in list)
{
domainUpDown1.Items.Add(item);
}
}
private List<string> get4000Strings()
{
List<string> l = new List<string>();
for (int i = 0; i < 4000; i++)
{
l.Add(i.ToString());
}
return l;
}
The DomainUpDown.Items collection has an AddRange() method that takes an ICollection (implemented by List<T>), so you could just do
private void Init() {
List<string> list = new List<string>();
list = get4000Strings(); //4000 items
domainUpDown1.Items.Clear();
domainUpDown1.Items.AddRange(list);
}
However, if you have that much items to show, I would suggest you use a ComboBox having DropDownStyle set to DropDownList.
It will allow you to databind directly to the list (e.g. comboBox1.DataSource = list;), especially if the list changes often, as you won't have to refill the ComboBox each time, just change the datasource...

Categories