3

I have a web service and in the code below I loop through a collection of items. These items are desplayed in an xml like fashion (see example below). However I would like to display them in table like fashion. I thought of using the datatable to insert the items in there and then redisplay them.

585344
        585344 Title Issue 1
        585344 Number 140024
        585344 State In progress
585350
        585350 Title Issue 2
        585350 Number 140026
        585350 State Classification

How can I display them like this:

ID        |  Title             |   Number    | State         
585344       issue 1               140024      In progress

   static void Main(string[] args)
    {
        ABWebService webSvc = new ABWebService();
        GetObjectListData gold = new GetObjectListData();

        gold.folderPath = "01. ITSM - Service Operation";
        gold.RequiredField = new RequiredField[3];
        gold.RequiredField[0] = new RequiredField {Value = "Title"};
        gold.RequiredField[1] = new RequiredField {Value = "Number"};
        gold.RequiredField[2] = new RequiredField {Value = "State"};

        try
        {
            GetObjectListResult golr = webSvc.GetObjectList(gold);

            List<NewsTracker> list = new List<NewsTracker>();
            if (golr.success)
            {
                ObjectData[] myObjects = golr.Object;
                for (int i = 0; i < myObjects.Length; i++)
                {
                    Console.WriteLine(myObjects[i].id);
                    foreach (object myItem in myObjects[i].Items)
                    {
                        string field1 = string.Empty;
                        string val1 = string.Empty;
                        int val2 = 0;
                        string field2 = string.Empty;

                        StringVal item = myItem as StringVal;
                        if (item != null)
                        {
                            field1 = item.name;
                            val1 = item.Value;
                            Console.WriteLine("\t" + myObjects[i].id + " " + field1 + " " + val1);

                        }

                        LongIntVal val = myItem as LongIntVal;
                        if (val != null)
                        {
                            field2 = val.name;
                            val2 = val.Value;
                            Console.WriteLine("\t" + myObjects[i].id + " " + field2 + " " + val2);

                        }

                    }
                }
            }

        }
        catch (Exception ex)
        {
            Console.WriteLine(ex.Message);
            throw;
        }
    }

EDIT 1:

can you tell me how can I add them in a generic list like this: list.Add(new NewsTracker(title,number,state)); so that I can loop through and do other things with the list?

Burre Ifort
  • 653
  • 3
  • 15
  • 30

2 Answers2

2

if you have only simple types then you can use reflection instead to build that table. here an example of a method i often use to send class info to a web service. Can be tweaked to receive a List and create 1 table with multiple rows once you understand the logic

public static DataTable ObjectToData(object o)
{
    DataTable dt = new DataTable("OutputData");
    DataRow dr = dt.NewRow();
    dt.Rows.Add(dr);

    o.GetType().GetProperties().ToList().ForEach(f =>
    {
        try
        {
            f.GetValue(o, null);
            dt.Columns.Add(f.Name, f.PropertyType);
            dt.Rows[0][f.Name] = f.GetValue(o, null);
        }
        catch { }
    });

    return dt;
}

If you pass the object ClassA per structure below

ClassA
{
    string Value1 = "abc";
    DateTime Value2 = DateTime.Now();
    int Value3 = 12;    
}

ObjectToData(MyClassA); datatable will look like the following :

|----------|-------------------------|----------|
|  Value1  |          Value2         |  Value3  |
|==========|=========================|==========|
|   "abc"  |  2015/10/30 08:00:00 AM |    12    |
|----------|-------------------------|----------|
Franck
  • 4,438
  • 1
  • 28
  • 55
  • Thanks for your answer, but can you tell me how can I add them in a generic list like this: `list.Add(new NewsTracker(title,number,state));` so that I can loop through and do other things with the list? – Burre Ifort Oct 31 '14 at 15:37
  • you mean creating a `List` from a datatable ? – Franck Nov 04 '14 at 12:23
  • No creating a List from looping through the myObjects[i].Items – Burre Ifort Nov 04 '14 at 14:16
  • the format for Linq if items are object type for example : `myObjects.Items.Cast().ToList().Select(o => new NewTracker(o.property1,o.propery2,...)).ToList()` this return a `List` object. i do suggest in the select you do it like so : `.Select(o => CreateNewTracker(o))`. creating a method that would return a `NewTracker` object would be easier to manage and do all reflection in a single space. Also this will allow you to reuse that method. – Franck Nov 04 '14 at 14:51
1

You could group by the key (ID in your example) and fill the other values accordingly. If you want a generic code, you could use some generic properties, correlating "name of column" and "value", like this:

Pseudo-code:

// Consider ID as the key (maybe int in your case) and GenericProperty as a class of just 2 properties: name of property and value.
List<YourClass> list;
Dictionary<ID, HashSet<GenericProperty>> dict = ConvertToDictionary(list); // Convert the list to a dictionary
// Aggregate values per ID (key)
// You can get the PropertyName with reflection

foreach (var pair in dict)
{
    var row = DataTable.Rows.AddRow();

    foreach (var values in pair.Value)
        row[pair.Value.PropertyName] = pair.Value.Value;
}

Note that if you don't need a generic code, than the class GenericProperty could be an specific class with all values as properties. In your example, 3 properties: title, number, state. Then you can use them to fill the DataTable. Example as follow:

Aditionally, you can get the property name and value with reflection (example here), or as Franck said.

EDIT (based on questions edit):

Let's make an example for "myObjects" object that you've shown.

If I understood correctly, "myObjects" is already your grouped list. So "myObjects.Items" are the values of one grouped key.

So we have:

List<NewsTracker> list = new List<NewsTracker>(myObjects.Count);
foreach (var obj in myObjects)
{
    // 'obj' is one key, so one value of NewsTracker
    NewsTracker nt = new NewsTracker();

    foreach (var item in myObjects.Items)
    {
        // Capture the name of the item and check what property is it from
        // Code you've show in your question. --> I'll consider that you already know how to get "fieldName" as with "value" (object)
        if (fieldName.Equals("Title"))
            nt.Title = (string)value;
        else if (fieldName.Equals("Number")
            nt.Number = (int)value;
        // ... and so on ...
     }
     // At the end of the inner loop, we must have a "NewsTracker" filled with the correct values, so now we only need to add them to the main list
     list.Add(nt);
}

Note: I've wrote an specific code to your problem considerind the 'NewsTracker' class.

Community
  • 1
  • 1
Iúri dos Anjos
  • 371
  • 4
  • 20