How to add nodes in treeview from a list - c#

I have following code where I require to create the node and sub node that is to bind with the list.
I am converting it to array then I am trying to add, but I fail to do this How should I do it? Following is my code:
foreach (var item in ProductCategory)
{
TreeNode tr = new TreeNode(item.CatName);
List<dataObject> lst = objFreecusatomization.GetAllCustomItems(CategoryType.Dressing, item.CategoryID);
TreeNode[] sumItemList =new TreeNode[lst.Count];
foreach (var subItem in lst)
{
sumItemList[sumItemList] = new TreeNode { Name = subItem.Name, Text = subItem.Name, Checked = subItem.Selected };
}
treeCustomItem.Nodes.Add(item.CatName, sumItemList);
}
And I also need to assign key value, name to the items being added. through LinQ or lambda-expression. What's the best way?

This will fail: sumItemList[sumItemList] = new TreeNode ... The index of an array cannot be the array itself.
Since you have no indexer (because of the foreach) I suggest you use a List, like this:
foreach (var item in ProductCategory)
{
TreeNode treeCustomItem = new TreeNode(item.CatName);
List<dataObject> lst = objFreecusatomization.GetAllCustomItems(CategoryType.Dressing, item.CategoryID);
List<TreeNode> sumItemList = new List<TreeNode>();
foreach (var subItem in lst)
{
sumItemList.Add(new TreeNode { ... });
}
treeCustomItem.Nodes.AddRange(sumItemList.ToArray());
}
But since you're already iterating over your fetched subitems, you can also add the subitems directly instead of using an array/list. Your inner foreach would become:
foreach (var subItem in lst)
{
treeCustomItem.Nodes.Add(new TreeNode { ... });
}

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());
}

Entity Framework: How to insert data while looping through multiple lists

I am attempting to insert data from two List.
I am able to successfully insert from one List but adding the second list using a foreach loop does not work as expected.
How do I loop through each of these list so that I can insert their values?
Code:
private void InsertList()
{
var listA = new List<string>();
var listB = new List<string>();
//Populate both list by splitting items in listbox
foreach (ListItem item in ListBox1.Items)
{
var components = item.Value.Split('/');
listA.Add(components.First());
listB.Add(components.Last());
}
using (DataContext dataContext = new DataContext())
{
foreach (var itemA in listA)
{
foreach (var itemB in listB)
{
LIST_OBJECTS listObject = new LIST_OBJECTS
{
LIST_ITEM_A = itemA,
LIST_ITEM_B = itemB
};
dataContext.LIST_OBJECTS.Add(listObject);
}
}
dataContext.SaveChanges();
}
}
What about a for loop?
for (var i = 0; i < listA.Count; i++)
{
LIST_OBJECTS listObject = new LIST_OBJECTS
{
LIST_ITEM_A = listA[i],
LIST_ITEM_B = listB[i]
};
dataContext.LIST_OBJECTS.Add(listObject);
}
Since you know from the creation of the Lists that they'll have the same number of elements, this is fine.
You can do it with LINQ
LIST_OBJECTS listObject = listA.Join(listB,
a=>listA.Indexof(a),
b=>listB.Indexof(b),
(a,b)=> new LIST_OBJECTS()
{
LIST_ITEM_A =a,
LIST_ITEM_B =b
}).ToList();

Loop through sections of a collection

Here is a loop I'm working on to create a JSON object collection:
var sb = new StringBuilder();
var list = DataAccess.Read.EventsByID(id);
foreach (var spevent in list)
{
sb.AppendFormat("'{0}':'{2}',",spevent.StartTimeDt.ToString("MM-dd-yyyy"), spevent.Link, spevent.Title);
}
The flaw is, if I have multiple events with the same date, I only get the last one because
window.eventscollection = {
'07-23-2013' : 'Item One',
'07-23-2013' : 'Item Two',
}
has two items with the same object name, and won't take duplicates.
The correct output would be to merge all items with the same date into one item as follows:
window.eventscollection = {
'07-23-2013' : 'Item OneItem Two',
}
It seems I need some kind of while or recursive loop to see if the next item has the same date as the current item and change the output, but I can't seem to get it right.
Thoughts?
You could group the items from the same date as
var sb = new StringBuilder();
var items = DataAccess.Read.EventsByID(id).GroupBy(p=>StartTimeDt.ToString("MM-dd-yyyy"));
then iterate through the grouping:
foreach (var item in items)
{
StringBuilder sb2 = new StringBuilder();
foreach(var subitem in item)
sb2.Append(String.Format("{2}",subitem.Link,subitem.Title));
sb.AppendFormat("'{0}':'{1}',",item.Key, sb2.ToString());
}
You first need to GroupBy on your list:
var sb = new StringBuilder();
var list = DataAccess.Read.EventsByID(id).GroupBy(e => e.StartTimeDt.Date);
And then you can loop within the loop
foreach (var dt in list)
{
sb.AppendFormat("'{0}'",dt.Key.ToString("yyyy-MM-dd"))
foreach (var spevent in dt)
{
sb.AppendFormat("'{1}',",, spevent.Link, spevent.Title);
}
}

For Each Element in Two Lists

This is my code:
List<string> l1 = new List<string> { "a", "b", "c" };
List<string> l2 = new List<string> { "x", "y", "z" };
foreach (var item in l1)
{
item = MyFunction(item);
}
foreach (var item in l1)
{
item = MyFunction(item);
}
Is there a way to iterate both the Lists in a single foreach statement ?
Assuming the type of the List objects are the same you can use Concat.
foreach (var item in l1.Concat(l2))
{
item = MyFunction(item);
}
You could use the Concat() function:
foreach(var item in l1.Concat(l2))
item = MyFunction(item);
Be aware that reassigning the counter variable of an Enumerable-based loop can cause exceptions relating to changing the underlying IEnumerable.
Maybe something like this:
var mergedList = 11.Union(l2).ToList();
foreach (var item in mergedList)
{
item = MyFunction(item);
}
The Union removes any duplicates. The Concat() method does not. So Union might be preferrable. It depends on the composition of the lists.

How to skip a specific position within a for each loop in c sharp?

List<string> liste = new List<String>
{
"A","B","C","D"
};
foreach (var item in liste)
{
System.Diagnostics.Debug.WriteLine(item.ToString());
}
for (int i = 0; i < liste.Count; i++)
{
if (i == 0)
continue;
System.Diagnostics.Debug.WriteLine(liste[i].ToString());
}
How do i skip a specific position in a foreach loop? I do not want to evaluate any values, but just skip the position x.
It has to be a specific position. One could choose position 0 or maybe position 7.
It is very easy to skip the first item in the list:
foreach(var item in list.Skip(1))
{
System.Diagnostics.Debug.WriteLine(item.ToString());
}
If you want to skip any other element at index n, you could write this:
foreach(var item in list.Where((a,b) => b != n))
{
System.Diagnostics.Debug.WriteLine(item.ToString());
}
In this example I use a lambda expression that takes two arguments: a and b. Argument a is the item itself, while argument b is the index of the item.
The relevant pages on MSDN that describe these extension methods are:
IEnumerable.Skip()
IEnumerable.Where()
You could even write your own extension method that allows you to skip an element in a list:
public static class MyEnumerableExtensions
{
public static IEnumerable<T> SkipAt<T>(this IEnumerable<T> list, int index)
{
var i = 0;
foreach(var item in list)
{
if(i != index)
yield return item;
i++;
}
}
}
This will allow you to write something like this to skip an item:
foreach(var item in list.SkipAt(2))
{
System.Diagnostics.Debug.WriteLine(item.ToString());
}
A foreach loop iterates over a collection that implements IEnumerable. The enumerator exposes the current item and a method to move onto the next item - it has no concept of an index.
You could always do:
var i = 0;
foreach (var item in liste) {
if (i++ == skip) continue;
Debug.WriteLine(item.ToString());
}
But this seems unnecessarily contrived. If you need an index, go with a for loop.
The other option is to remove the undesired item from the List before iterating:
foreach (var item in liste.Take(n-1).Union(liste.Skip(n))) {
Debug.WriteLine(item.ToString());
}
I love list's .ForEach, here's my take using #Elian's .SkipAt(n) and .ForEach:
var list = new List<String> { "A", "B", "C", "D" };
list = list.SkipAt(1).ToList();
list.ForEach(Debug.WriteLine);
You should try using the enhanced version of the Where extension method that allows you to filter on item and index.
Check the reference.
http://msdn.microsoft.com/en-us/library/bb549418.aspx
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
namespace ConsoleApplication1
{
class Program
{
static void Main(string[] args)
{
Console.WriteLine("Verbatim list");
List<string> list = new List<String> { "A","B","C","D" };
foreach (var item in list)
{
Console.WriteLine(item.ToString());
}
Console.WriteLine("Filtered list");
int itemToSkip = 2;
foreach (var item in list.Where((item, index) => index != itemToSkip))
{
Console.WriteLine(item.ToString());
}
Console.ReadKey();
}
}
}
This will give you the following output.
Verbatim list
A
B
C
D
Filtered list
A
B
D
To skip a position inside the foreach loop, one option is that you can skip the action inside the foreach loop by using an if statement, like
foreach(var item in liste)
{
if (item != 'X')
{
//do something
}
}
But i am waiting for better solutions

Categories