0

good afternoon guys and girls! i am trying to learn c#(WPF) for about 2 weeks now and i'm encountering some problems which google didnt help me to solve so far :/

Lets say i have a random XML file:

<?xml version="1.0" encoding="UTF-8"?>
<XML>
  <ADRESSE>
    <NAME1>John</NAME1>
    <NAME2>Doe</NAME2>
    <STRASSE1>Heystreet</STRASSE1>
    <STRASSE2>9</STRASSE2>
    <LAND>AUT</LAND>
    <PLZ>1050</PLZ>
    <ORT>Vienna</ORT>
  </ADRESSE>
</XML>

Pretend this XML has like 100 entries.

Now i'll have a simple Listview called "lv1" in my XAML and a button.

        int counter = 0;
        GridView gv1 = new GridView();
        XDocument rndfile = XDocument.Load(@"C:\Users\...\random.xml");

        foreach (XElement xele in rndfile.Descendants("ADRESSE")) //#1
        {

            GridViewColumn gvc = new GridViewColumn();
            gvc.DisplayMemberBinding = new Binding("Feld"+counter); 
            gvc.Header = xele.Name.LocalName; // #2
            gv1.Columns.Add(gvc); 
            string feldx = string.Format(@"Feld{0}", counter);
           // MessageBox.Show(feldx+"||"+"Feld"+counter); //was for me to test if names are identical
            lv1.Items.Add(new { feldx = xele.Element("Childelement of ADRESSE").Value }); //#3+4
            counter++;

        }
        lv1.View = gv1;

1 and 3 are my actual problems, whereby 1 and 2 are the same thing i guess.

So basically what i want to do is press the Button, load the XML and create for each Child of ADRESSE a column with the name of the current Child and directly fill it with the XML content.

The problems i am encountering now: #1 the foreach loop only runs for each entry called ADRESSE instead of each child element of it and i just cant figure out how to get the childs of it without breaking any syntax (tried it with Elements() but he doesnt like that in the loop then).. So for now the XML above would only create ONE row instead of 7, because theres only one ADRESSE entry in the file.

For the second problem i want to name the Columns with the Childname of the XML, but due to the problem at #1 it wont work as intended. (or is this thought generally wrong?)

And the third problem is the dynamical filling of the columns. As far as i could see it lv1.Items.Add({...}) does not accept the feldx from above, but thinks it is a own name and doesn't fill it correctly then, because there are no columnbindings named feldx. For #4 i need something like feldx = xele.Element(@"{0}", ChildName).Valuefor the correct content of the column then

I really tried to look and solve this on my own, but all stuff i found on XML or gridviews here or at mycsharp/msdn either was only with static (hardcoded) XAML entrys and bindings or just XML files where you know what entrys there are (so again practically hardcoded). So i just hope my request just isn't too barefaced and someone could enlighten me a little

Edit #1 :

    var rootele = rndfile.Root.Element("ADRESSE").Elements(); //<-- worked like a charm. My problem was that i tried to fiddle this into the foreach loop itself, which wasn't accepted somehow - so many thanks har07
    int counter = 0;
    foreach (XElement xele in rootele)
    {
        GridViewColumn gvc = new GridViewColumn();
        gvc.DisplayMemberBinding = new Binding("Feld"+counter); 
        gvc.Header = xele.Name.LocalName; 
        gv1.Columns.Add(gvc); 
        lv1.Items.Add(new { feld_x_ = xele.Element("Childelement of ADRESSE").Value }); // <-- for this i am trying to find a solution and post it again, or maybe someone else knows how to add a changing Binding Name  into the .Add()
        counter++;

    }
    lv1.View = gv1;
Holunder
  • 3
  • 3

3 Answers3

0

Your XML file is incorrect.

<NAME2>Doe</NAME3> 

should be

<NAME2>Doe</NAME2>
SlopTonio
  • 1,105
  • 1
  • 16
  • 39
0

Your foreach loop is obviously tell to loop through each <ADRESSE> node, you can fix it like one of the following :

//approach 1 :
var chldNodes = rndfile.Descendants("ADRESSE").First().Elements();
//or approach 2 :
var chldNodes = rndfile.Root.Element("ADRESSE").Elements();
//then loop through childNodes
foreach (XElement xele in chldNodes)

3 & 4 looks simply wrong. That way, even if it worked, you'll ended with multiple rows, one for each column with corresponding row's column filled with value from XML and the rest columns are empty. Fix 1 & 2 then you can focused on 3 & 4, edit the question with your closest try -or open new question- if you can't make it work at the end.

EDIT :

Quick searching on google suggests that ListView with dynamic column seems not a trivial task (some related threads: 1, 2)

You may want to try this way (crafted based on link no. 2 above) :

....
var columnValues = new List<string>();
foreach (XElement xele in rootele)
{
    GridViewColumn gvc = new GridViewColumn();
    gvc.DisplayMemberBinding = new Binding(String.Format("[{0}]", counter)); 
    gvc.Header = xele.Name.LocalName; 
    gv1.Columns.Add(gvc); 
    columnValues.Add((string)xele);
    counter++;
}
lv1.Items.Add(columnValues);
....
Community
  • 1
  • 1
har07
  • 88,338
  • 12
  • 84
  • 137
  • shall i give you a 'solved answer' click or can i only give this once per thread? since you solved practically the main problem of my loop :) – Holunder Jul 30 '14 at 11:19
  • updated my answer for the rest problem. Though, I'd suggest to open new question if my update doesn't work for you – har07 Jul 30 '14 at 12:04
  • For the case with just one Entry in the XML this works perfectly, but not if you have multiple instances in the external xml.I am just playing around with this right now, but i am wondering why the Binding does only work with exactly this one you wrote above "String.Format("[{0}]", counter)". If i try to change the Binding name it doesnt work at all ? – Holunder Jul 30 '14 at 13:41
  • And i somehow assume that it won't work as intended if the XML file has its entries shuffled a little bit. What i mean is, that the example above adds the values directly into the created column, whereby it should add the values depending on the binding of the columns.. but you helped me so much already, i'll try to solve this either with two seperate foreach loops: one to create the Listview columns depending on the number of Childs of ADRESSE and one loop to add the values for each ADRESSE entry in the whole XML file) or try to get the variable names somehow into the lv1.Add.Items command – Holunder Jul 30 '14 at 13:42
  • 1) About the binding, yes it means "bind to `columnValues[counter]`", you can't randomly modify it. 2) That's because we only get the first `` -intentionally I thought- by doing this : `rndfile.Root.Element("ADRESSE")....` (notice `Element` instead of `Elements`). You need to change the logic flow quite radically if you meant to accommodate multiple ``, because at the moment the code will end up adding duplicate columns again and again for each ``. I'd suggest to rethink of the logic again, open new question if you need further advice. – har07 Jul 30 '14 at 13:57
0

I'll just write the partial Solution to this now, which will require some more hardcoding than i wanted, but better than nothing - maybe someone else needs it (Many Thanks again to har07)

        GridView gv1 = new GridView();
        XDocument rndfile = XDocument.Load(@"C:\Users\...\rndfile.xml");
        var rootele = rndfile.Descendants("ADRESSE").First().Elements();
        int counter = 0;
        //Create empty Listview depending on Sub-entrys of ADRESSE
        foreach (XElement xele in rootele)
        {

            GridViewColumn gvc = new GridViewColumn();
            gvc.DisplayMemberBinding = new Binding("Feld"+counter);//gets a Binding name Feld# for each child
            gvc.Header = xele.Name.LocalName; //Name my Columns after the <tags> of the childs
            gv1.Columns.Add(gvc);  //add the current Column to my Gridview
            counter++;

        } //Listview created

        //Fill my list for every single Parent-element in my XML file

            foreach (XElement xe in rndfile.Descendants("ADRESSE"))
            {

                 lv1.Items.Add(new
                    {
                        Feld0 = xe.Element("NAME1").Value,
                        Feld1 = xe.Element("NAME2").Value,
                        Feld2 = xe.Element("STRASSE1").Value,
                        Feld3 = xe.Element("STRASSE2").Value,
                        Feld4 = xe.Element("LAND").Value,
                        Feld5 = xe.Element("PLZ").Value,
                        Feld6 = xe.Element("ORT").Value
                    });

            }//List filled 

This way it doesn't matter in which order i have the ChildElements in the subsequent ADRESSE tags AFTER my first (Since the first Parent is needed to create the columns correctly). So the second shuffled Entry of ADRESSE below :

    <?xml version="1.0" encoding="UTF-8"?>
    <XML>
      <ADRESSE>
        <NAME1>John</NAME1>
        <NAME2>Doe</NAME2>
        <STRASSE1>Heystreet</STRASSE1>
        <STRASSE2>9</STRASSE2>
        <LAND>AUT</LAND>
        <PLZ>1050</PLZ>
        <ORT>Vienna</ORT>
      </ADRESSE>
      <ADRESSE>
        <LAND>AUT</LAND>
        <PLZ>1060</PLZ>
        <ORT>Vienna</ORT>
        <NAME1>Jane</NAME1>
        <STRASSE1>Wherestreet</STRASSE1>
        <STRASSE2>11</STRASSE2>
        <NAME2>Doe</NAME2>
      </ADRESSE>
    </XML>

Will still be filled in the correct Columns. Only Problems left now are the dependance of the Bindings (or namings of the Columns) on the First Entry and that i have to rename every X in all FeldX = xe.Element("XXX").Value if i use another kind of XML with different entries.

Still: if anyone knows a solution close to (i know that's completely broken but) something like ->

lv1.Items.Add(new{ string.Format(@"Feld{0}", counter) = xe.Element(@"{0}", xele.Name.LocalName).Value} 

to put into a loop i'd be really grateful!

Holunder
  • 3
  • 3