Autor |
Beitrag |
implicit
      
Beiträge: 36
|
Verfasst: Mi 01.07.09 16:33
Hallo,
Ich suche hier mal wieder einen kleinen Tip oder sogar eine Loesung.
Folgendes Szenario:
Es wird durch einer treeView- Auswahl ein bestimmter treeNode selectiert. Dieser gibt ein Attribute zurueck und veranlasst wieder rum ein Auslesen von verscheidenen, zu dem Node mit Attribute gehoerenden, Daten. Hier soll ebenfalls ein 2ter treeView mit bestimmten ChildNodes populiert werden. Ich habe es hinbekommen das er einen bestimmten ausliest und in einen treeView schreibt. Leider ohne childNodes.
Ok, soweit die Theorie. Ich lese folgende XML mit Linq ein.
XML-Daten 1: 2: 3: 4: 5: 6: 7: 8: 9: 10: 11: 12:
| <Server Typ="DL320 G1"> <Error> </Error> <Error1> Error2</Error1> <Error2> Error3</Error2> <Error3> Error3</Error3> </Server> <Server Typ="DL320 G2"> <Error>DL320 G2, Error1</Error> <Error1> Error2</Error1> <Error2> Error3</Error2> <Error3> Error3</Error3> </Server> |
Nun vergleicht er den ersten Wert aus einer XML.
1: 2: 3: 4: 5: 6: 7: 8: 9: 10: 11: 12: 13: 14: 15: 16: 17: 18: 19: 20: 21: 22: 23: 24: 25: 26: 27: 28: 29: 30: 31: 32: 33: 34: 35: 36: 37: 38: 39: 40: 41: 42: 43: 44: 45: 46: 47: 48: 49: 50: 51: 52: 53: 54: 55:
| private void troubleshootTV_AfterSelect(object sender, TreeViewEventArgs e) { serverdata(troubleshootTV.SelectedNode.Text); try {
string xmlItem = troubleshootTV.SelectedNode.Text; string treeViewRootNode = "Known Issue"; string xmlfilepath = Application.StartupPath + "\\tsdb\\troubleshootTree.xml";
XDocument xmlfile = XDocument.Load(xmlfilepath);
tstreeTV.Nodes.Clear(); tstreeTV.Nodes.Add(new TreeNode(treeViewRootNode));
TreeNode tNode = new TreeNode(); tNode = tstreeTV.Nodes[0]; var ErrorList = from Server in xmlfile.Descendants("Server") where Server.Attribute("Typ").Value == xmlItem select new { treeNode = Server.Element("Error").Value, }; foreach (var Server in ErrorList) { try { tstreeTV.Nodes.Add(new TreeNode(Server.treeNode)); } catch (XmlException xmlEx) { MessageBox.Show(xmlEx.Message); } catch (Exception ex) { MessageBox.Show(ex.Message); }
} this.tstreeTV.CollapseAll(); }
catch (Exception ex) { MessageBox.Show(ex.Message, "fehler"); } } |
Die anze sache klappt auch, aber liest mir nicht die kompletten childnodes mit ein sondern nur den node den ich unter Select new angebe.
Wie kann ich ihm eine Schleife schreiben das er die childNodes des unter der variable treeNode ausgelesenen Node in einen treeView populiert ?
Danke fuer eure Bemuehungen schon im Vorraus.
P.S. Ja ich habe eine etwas komische Namensgebung der Variabeln und Objekten, Aber dafuer komme ich mit diesen Besser klar. 
|
|
Kha
      
Beiträge: 3803
Erhaltene Danke: 176
Arch Linux
Python, C, C++ (vim)
|
Verfasst: Mi 01.07.09 18:48
Du suchst doch nur genau einen <Server>-Node, also:
C#-Quelltext 1:
| XElement server = xmlFile.Descendants("Server").Single(el => el.Attribute("Typ").Value == xmlItem); |
Dafür erstellst du dann einen TreeNode und hängst in einer Schleife über server.Elements() die Kindknoten an.
implicit hat folgendes geschrieben : | P.S. Ja ich habe eine etwas komische Namensgebung der Variabeln und Objekten, Aber dafuer komme ich mit diesen Besser klar.  |
Überlege dir wenigstens, ob du lokale Variablen nun klein oder groß schreibst  .
_________________ >λ=
|
|
implicit 
      
Beiträge: 36
|
Verfasst: Mi 01.07.09 18:58
huhu
Genau ich suche nur einen Server Node und moechte danach die KindKnoten in den treeView anyeigen lassen.
Aber genau da ist der Hund verkraben.
Wie kann ich nun von genau diesem Knoten die Kindknoten auslesen und in dem treView darstellen ? Wichtig ist das die Anyahl dabei keine Rolle spielen darf. Er soll schoen fein sauber die Kindknoten mit den Kindeskinderknoten usw usw. darstellen.
Kannst Du mir da nen Tip geben wie ich diese Schleife arangieren kann?
|
|
Kha
      
Beiträge: 3803
Erhaltene Danke: 176
Arch Linux
Python, C, C++ (vim)
|
Verfasst: Mi 01.07.09 19:12
|
|
implicit 
      
Beiträge: 36
|
Verfasst: Mi 01.07.09 20:24
OK,
Jetzt haste mich mal komplett verwirrt. Wie soll ich diesen Code verstehen bzw. was macht der ?
C#-Quelltext 1:
| XElement server = xmlFile.Descendants("Server").Single(el => el.Attribute("Typ").Value == xmlItem); |
Also Du suchst in der xmlfile all Descendants von Server raus. Was macht der code?
.Single(el => el.Attribute("Typ").Value == xmlITem);
.. der Vergleicht den "Single" Wert der Descendants von Server mit xmlItem?
ist das net das selbe, wie der code hier ? Bzw. wuerdest Du mir Bitte den Sachverhalt erklaeren?
C#-Quelltext 1: 2:
| var ErrorList = from Server in xmlfile.Descendants("Server") where Server.Attribute("Typ").Value == xmlItem |
Wenn er dann den richtigen Node gefunden hat, soll ich den dann nicht selectieren mit "select new" ?
sondern ich mache einfach deine recurse schleife einsetzen? also statt diese foreach
C#-Quelltext 1: 2: 3: 4: 5: 6: 7: 8: 9: 10: 11: 12: 13: 14: 15: 16:
| foreach (var Server in ErrorList) { try { tstreeTV.Nodes.Add(new TreeNode(Server.treeNode)); } catch (XmlException xmlEx) { MessageBox.Show(xmlEx.Message); } catch (Exception ex) { MessageBox.Show(ex.Message); }
} |
Deine Recurse?
C#-Quelltext 1: 2: 3: 4: 5: 6: 7:
| void Recurse(XElement element, TreeNode node) { foreach (var child in element.Elements()) { var childNode = node.Nodes.Add(child.Name); Recurse(child, childNode); } } |
verdammt, ich stehe gerade oso auf dem schlauch...  Sorry kannst Du mir das irgendwie erklaerend schreiben ? Bitte !!!
Gruss Steffen
|
|
Kha
      
Beiträge: 3803
Erhaltene Danke: 176
Arch Linux
Python, C, C++ (vim)
|
Verfasst: Mi 01.07.09 21:35
Tja, jetzt wären wir wieder beim Jonglier-Problem  . Linq ist das Komplexeste, was C# hergibt, und die meisten 08/15-Programmierer werden sich erst gar nicht damit anlegen. Also gehe ich umgekehrt davon aus, dass jemand, der sich damit beschäftigt, sowieso schon C#-firm ist und ich im Zweifelsfalle nichts erklären muss, sondern einfach Code sprechen lasse ^^ . Also, Schritt für Schritt:
implicit hat folgendes geschrieben : | .. der Vergleicht den "Single" Wert der Descendants von Server mit xmlItem? |
Siehst du in der Hilfe eine XElement.Single-Methode  ? Single ist wie Where und die anderen Linq-to-Objects-Methoden eine Extension Method von IEnumerable<T>.
Bei deiner Query hast du ja deine ErrorList von Objekten zurückbekommen und dann eine foreach-Schleife darübergejagt, aber du erwartest doch eigentlich nur ein Objekt zurück. Dafür gibt es Single, hier erstmal die parameterlose Variante:
C#-Quelltext 1: 2: 3: 4:
| csharp> new[]{ 1 }.Single(); 1 csharp> new[]{ 1 , 2 }.Single(); System.InvalidOperationException: Operation is not valid due to the current state of the object |
Die Version mit Parameter ist einfach die Faulheitsvariante mit integriertem Where, du könntest meine Single-Zeile auch so schreiben:
C#-Quelltext 1:
| xmlFile.Descendants("Server").Where(el => el.Attribute("Typ").Value == xmlItem).Single(); |
oder
C#-Quelltext 1: 2: 3:
| (from el in xmlFile.Descendants("Server") where el.Attribute("Typ").Value == xmlItem select el).Single(); |
Jetzt hast du den <Server>-Node in einem XElement, so könnte es für die direkten Kinder weitergehen:
C#-Quelltext 1: 2:
| foreach (var error in server.Elements()) tstreeTV.Nodes.Add(error.Value); |
Bei den Kindeskindern müsstest du mal die XML-Struktur zeigen.
Jetzt einigermaßen klar  ?
implicit hat folgendes geschrieben : | Wenn er dann den richtigen Node gefunden hat, soll ich den dann nicht selectieren mit "select new" ? |
In der "Query-Form" brauchst du abschließend zwar immer ein select oder group by, aber dass es in der "Extension-Method-Form" auch ohne geht, habe ich ja oben gezeigt. Und eine anonyme Klasse ( new{...}) mit einer einzigen Property macht selten Sinn  . Vor allem brauchst du eben noch das Server-XElement, um an die Kinder zu kommen.
Und zum Abschluss jetzt alles in einer Anweisung  .
C#-Quelltext 1: 2: 3: 4: 5: 6:
| tstreeTV.Nodes.AddRange( (from errorNode in (from el in xmlFile.Descendants("Server") where el.Attribute("Typ").Value == xmlItem select el).Single().Elements() select new TreeNode(errorNode.Value)).ToArray()); |
Uuuund zur Übung das jetzt bitte in Extension-Method-Form  ² .
_________________ >λ=
|
|
implicit 
      
Beiträge: 36
|
Verfasst: Mi 01.07.09 22:00
Hey,
genial, bist Du Lehrer oder sowas ? Verdammt gut erklaert .. Jetzt habe ich das auch verstanden.
Diese XElement class hatte ich ganz vergessen, die bringt ja schon einiges mit sich.
Ich werde mich morgen mal mit deinen Beispielen und den snippes beschaeftigen.. Fuer jetzt erstmal Danke fuer die Erklaerungen.
Gruss
|
|
implicit 
      
Beiträge: 36
|
Verfasst: Do 02.07.09 12:30
Hallo kha,
habe den code mal implementiert. echt verdammt machtvolle zeilen.  ich haette glaube ich 30 anweisungen mehr geschrieben
Weitere Frage habe ich allerdings.. das mit den KindesKinderNodes...
Meine ich folgendermassen.
Jetzt generiert er fuer jeden Kindnode einen Haupttreenode.
XML-Daten 1: 2: 3: 4: 5: 6: 7: 8:
| <Server Typ="DL320 G1"> <Error> Error1 <Issue> Port defekt</Issue> </Error> <Error1> Error2</Error1> <Error2> Error3</Error2> <Error3> Error3</Error3> </Server> |
Quelltext 1: 2: 3: 4: 5:
| [-]Root |_[Error1 Port defekt] |_[Error2] |_[Error3] ... |
Er soll aber aus dieser XML die Kindeskinder auch weiter als Kind des "Error" nodes behandeln und folgender massen eintragen.
Quelltext 1: 2: 3: 4: 5: 6:
| [-]Root |_[Error1] |_[Port defekt] |_[Error2] |_[Error3] ... |
Muss ich hier irgendwie in dem Array ein xmlNodeList anlegen ? oder wie wuerdest Du das Loesen ?
Ich gleube das meinst du mit der Uebung  Oder ?
Zitat: | Uuuund zur Übung das jetzt bitte in Extension-Method-Form ² |
Ich versuche mich mal weiter, mit diesem XElement  und der Extension-Methode-Form...
Danke schonmal fuer Deine Zeit...
Gruss Steffen
|
|
Kha
      
Beiträge: 3803
Erhaltene Danke: 176
Arch Linux
Python, C, C++ (vim)
|
Verfasst: Fr 03.07.09 12:52
implicit hat folgendes geschrieben : | genial, bist Du Lehrer oder sowas ? |
Nicht ganz, bis letzte Woche war ich Schüler  ...
Etwas merkwürdige XML-Struktur, besonders das Error/Error1/Error2/...  . Ich nehme an, darauf hast du keinen Einfluss?
Sei's drum: Wir sind jetzt also im Inneren meiner foreach (var error in server.Elements())-Schleife. Der Text vor dem Issue-Tag wird als XText-Objekt repräsentiert, du kommst über error.FirstNode und einen Cast an es heran. Mit dessen Value-Property kannst du nun also deinem TreeView einen Knoten hinzufügen.
Und diesem Knoten fügst du dann für jedes XElement in error.Elements("Issue") noch einen Unterknoten hinzu.
Ich hoffe, diese knappe, code-lose Erklärung genügt erstmal, sonst einfach nachfragen  .
implicit hat folgendes geschrieben : | Muss ich hier irgendwie in dem Array ein xmlNodeList anlegen? |
Bis jetzt hatten wir noch kein Array  . Und wir werden auch keine Liste brauchen, foreaches über die XElement-Properties werden genügen.
Die Übung war noch auf meinen Code ohne Kindeskinder bezogen.
_________________ >λ=
|
|
implicit 
      
Beiträge: 36
|
Verfasst: Fr 03.07.09 13:52
Ah da isser wieder
Ja also, warte ich zeige dir mal die XML wie sie im ganzen ausehen soll dann.
XML-Daten 1: 2: 3: 4: 5: 6: 7: 8: 9: 10: 11: 12: 13: 14: 15:
| <Server Typ="DL320 G1"> <Error>Dl320g2, Proliant DL <Issue> Battery defect <Solution1> Firmware checked and compaired to 2.54 <fixing> replace battery</fixing> </Solution1> <Solution2> Firmware checked and below 2.54 <fixing> update Firmware</fixing> </Solution2> </Issue> <Issue> Error2</Issue> <Issue> Error3</Issue> <Issue> Error3</Issue> </Error> </Server> |
Also das ganze tool soll bestimmte Loesungswege aus einem XML file ziehen. Also da ich diese XML Datenbankselber "erfinde"
habe ich einen Einfluss auf die struckture und Daten.
Zitat: | Sei's drum: Wir sind jetzt also im Inneren meiner foreach (var error in server.Elements())-Schleife. Der Text vor dem Issue-Tag wird als XText-Objekt repräsentiert, du kommst über error.FirstNode und einen Cast an es heran. Mit dessen Value-Property kannst du nun also deinem TreeView einen Knoten hinzufügen.
Und diesem Knoten fügst du dann für jedes XElement in error.Elements("Issue") noch einen Unterknoten hinzu. |
genau hier haengt der knoten. Ich habe verstanden das du einfach von dem bestimmten XElement die Kinder ausliest und dem treeView via addRange und anonyme Variable bestimmte Knoten anfuegst. Dabei nimmt aber dieses addRange nur Arrays an.
Ich weiss nun nicht wie ich dem treeView begreiflich mache das er diese "SUBNODES" nicht als Array hinzufuegt sondern schoen fuer jeden Node einen neuen Subtree anlegt.
Das muss ich mit einer foreach schleife basteln, richtig ?
Zitat: | Bis jetzt hatten wir noch kein Array . Und wir werden auch keine Liste brauchen, foreaches über die XElement-Properties werden genügen.
Die Übung war noch auf meinen Code ohne Kindeskinder bezogen. |
Aber Du uebergist doch deinen "select" aus der xml via array an den treeView.addRange.
C#-Quelltext 1:
| tstreeTV.Nodes.AddRange((from errorNode in .... |
Gruss Steffen
|
|
Kha
      
Beiträge: 3803
Erhaltene Danke: 176
Arch Linux
Python, C, C++ (vim)
|
Verfasst: Fr 03.07.09 14:16
implicit hat folgendes geschrieben : | Ah da isser wieder  |
Jo, kurzer Abstecher zu "The Boss" nach München  .
implicit hat folgendes geschrieben : | Ja also, warte ich zeige dir mal die XML wie sie im ganzen ausehen soll dann. |
Na endlich ;P .
implicit hat folgendes geschrieben : | Aber Du uebergist doch deinen "select" aus der xml via array an den treeView.addRange. |
Kleines Missverständnis: Der "  " sollte eigentlich aussagen, dass der AddRange-Code nicht ganz ernstgemeint war  . Wie es mit foreach und Add funktioniert, habe ich ja darüber gezeigt.
Da deine Struktur ab <Error> so gleichförmig ist, könnten wir es wirklich mit Rekursion versuchen. Ich würde sie allerdings folgendermaßen abändern, das erleichtert das Einlesen ein wenig und ist imho "XML-iger":
XML-Daten 1: 2: 3: 4: 5: 6: 7: 8: 9: 10: 11:
| <Error Description="Dl320g2, Proliant DL"> <Issue Description="Battery defect"> <Solution Description="Firmware checked and compaired to 2.54"> <fixing Description="replace battery" /> </Solution> <Solution Description="Firmware checked and below 2.54"> <fixing Description="update Firmware" /> </Solution> </Issue> <Issue Description="..." /> </Error> |
C#-Quelltext 1: 2:
| foreach (var error in server.Elements()) Recurse(error, tstreeTV.Nodes); |
C#-Quelltext 1: 2: 3: 4: 5: 6:
| void Recurse(XElement element, TreeNodeCollection parent) { TreeNode node = parent.Add(element.Attribute("Description").Value()); foreach (var child in element.Elements()) Recurse(child, node); } |
_________________ >λ=
|
|
implicit 
      
Beiträge: 36
|
Verfasst: Fr 03.07.09 15:38
hehe,
ok also das war nen coder witz mit addrange  . Du wirst es net glauben aber er hat fast genau das gemacht was ich erwartet hatte
ok ich aendere das XML file so ab. Hast Recht ist eine bessere XML strukture.
Problem ist nun nur noch die Einbindung der recurse.
Ich lasse den "Vergleich" immernoch stehen..
und "selektiere" mit select den "errorNode" ?
select new TreeNode(errorNode.Value)).ToArray());
und danach schiebe ich die foreach schleife drueber.. aber wie binde ich die recurse da ein ?
C#-Quelltext 1: 2: 3: 4: 5: 6:
| void Recurse(XElement element, TreeNodeCollection parent) { TreeNode node = parent.Add(element.Attribute("Description").Value()); foreach (var child in element.Elements()) Recurse(child, node); } |
Total verwirrt bin.
|
|
Kha
      
Beiträge: 3803
Erhaltene Danke: 176
Arch Linux
Python, C, C++ (vim)
|
Verfasst: Sa 04.07.09 13:52
implicit hat folgendes geschrieben : | Du wirst es net glauben aber er hat fast genau das gemacht was ich erwartet hatte  |
Scheinbar immer noch nicht ganz klar  : Die einzelnen in meiner Erklärung verteilten Zeilen stellen die Add-Lösung dar, wie ich sie selbst geschrieben hätte. Der AddRange-Code sollte einfach zeigen, wie man den Code auch schreiben könnte, ohne dass sich am Verhalten etwas ändert.
Sammeln wir also mal meine verstreuten Zeilen ein:
C#-Quelltext 1: 2: 3: 4: 5: 6: 7: 8: 9: 10: 11: 12:
| XElement server = xmlFile.Descendants("Server").Single(el => el.Attribute("Typ").Value == xmlItem); foreach (var error in server.Elements()) Recurse(error, tstreeTV.Nodes);
...
void Recurse(XElement element, TreeNodeCollection parent) { TreeNode node = parent.Add(element.Attribute("Description").Value()); foreach (var child in element.Elements()) Recurse(child, node); } |
Das war's, so sollte es passen.
_________________ >λ=
|
|
implicit 
      
Beiträge: 36
|
Verfasst: Di 07.07.09 14:11
Hallo Kha,
Also ich habe etwas Zeit gefunden Deinen Code eingebunden, jedenfalls versucht.
C#-Quelltext 1: 2: 3: 4: 5: 6: 7: 8: 9: 10: 11: 12: 13: 14: 15: 16: 17: 18: 19:
| private void populatetstree(string inputdata) {
string xmlItem = inputdata; string xmlfilepath = Application.StartupPath + "\\tsdb\\troubleshootTree.xml"; XDocument xmlFile = XDocument.Load(xmlfilepath); XElement server = xmlFile.Descendants("Server").Single(el => el.Attribute("Typ").Value == xmlItem); foreach (var error in server.Elements()) Recurse(error, tstreeTV.Nodes); }
void Recurse(XElement element, TreeNodeCollection parent) { TreeNode node = parent.Add(element.Attribute("Description").Value); foreach (var child in element.Elements()) Recurse(child, node); } |
er meckert allerdings die zeile an: Recurse(child, node);
Irgendwie kann er den "node" nicht in einen TreeNodeCollection eintragen
Quelltext 1:
| Error 1 The best overloaded method match for 'WindowsFormsApplication4.Form1.Recurse(System.Xml.Linq.XElement, System.Windows.Forms.TreeNodeCollection)' has some invalid arguments |
Und Hier sagt er es auch noch gaaaanz frech ...
Error 2 Argument '2': cannot convert from 'System.Windows.Forms.TreeNode' to 'System.Windows.Forms.TreeNodeCollection'
So richtig funzt die recurse methode net .. ich werde mich mal weiter mit diesen Fehlern beschaeftigen.
Gruss Steffen 
|
|
Kha
      
Beiträge: 3803
Erhaltene Danke: 176
Arch Linux
Python, C, C++ (vim)
|
Verfasst: Di 07.07.09 14:16
Ersetze node durch node.Nodes  ...
_________________ >λ=
|
|
implicit 
      
Beiträge: 36
|
Verfasst: Di 07.07.09 20:09
OHman.
bin ich d)piep=
ok funzt... danke .. kha.. 
|
|
|