XMLDocument 1:1 in TreeView füllen



  • Moin,

    wahrscheinlich stell ich mich einfach zu blöd an.Aber ich versuche die janze zeit ein Verkacktes XML-dokuemt in einen TreeView zu füllen.Natürlich soll die Struktur erhalten bleiben wie sie im XML ist.
    Ich komm einfach auf die Rekursion nicht klar, eventuell gibt mal jemand nen kurzen Denkanstoß.

    Hier die Funktion:

    private TreeNode GetXmlAttributes(XmlNode root,TreeNode n)
            {   
    
                foreach (XmlNode daten in root.ChildNodes)
                {
                        n.Nodes.Add(daten.Name);
                        n = this.GetXmlAttributes(daten, n);
                }
                return n;
            }
    

    und hier der aufruf:

    XmlDocument doc = new XmlDocument();
                    doc.Load(openFileDialog_xmldatei.FileName);
                    XmlElement root = doc.DocumentElement;
                    treeView_xmltree.Nodes.Add(this.GetXmlAttributes(root,new TreeNode()));
    


  • Wie tief ist denn deine Rekursion?

    Edit: Was funktioniert denn nun eigentlich nicht, wird das Objekt nicht befüllt, kommt ne Exception, deinstalliert sich Windows?



  • Kommt auf das XML-File an würde ich sagen.
    Hier mal ein XML-File was der .csproj Datei enspricht von VisualStudio.

    <?xml version="1.0" encoding="utf-8"?>
    <Project ToolsVersion="3.5" DefaultTargets="Build" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
      <PropertyGroup>
        <Configuration Condition=" '$(Configuration)' == '' ">Debug</Configuration>
        <Platform Condition=" '$(Platform)' == '' ">AnyCPU</Platform>
        <ProductVersion>9.0.30428</ProductVersion>
        <SchemaVersion>2.0</SchemaVersion>
        <ProjectGuid>{F69E4DCA-81B7-4614-89B5-C37F90841C46}</ProjectGuid>
        <OutputType>Exe</OutputType>
        <AppDesignerFolder>Properties</AppDesignerFolder>
        <RootNamespace>StringBuilderTest</RootNamespace>
        <AssemblyName>StringBuilder</AssemblyName>
        <TargetFrameworkVersion>v3.5</TargetFrameworkVersion>
        <FileAlignment>512</FileAlignment>
      </PropertyGroup>
      <PropertyGroup Condition=" '$(Configuration)|$(Platform)' == 'Debug|AnyCPU' ">
        <DebugSymbols>true</DebugSymbols>
        <DebugType>full</DebugType>
        <Optimize>false</Optimize>
        <OutputPath>bin\Debug\</OutputPath>
        <DefineConstants>DEBUG;TRACE</DefineConstants>
        <ErrorReport>prompt</ErrorReport>
        <WarningLevel>4</WarningLevel>
      </PropertyGroup>
      <PropertyGroup Condition=" '$(Configuration)|$(Platform)' == 'Release|AnyCPU' ">
        <DebugType>pdbonly</DebugType>
        <Optimize>true</Optimize>
        <OutputPath>bin\Release\</OutputPath>
        <DefineConstants>TRACE</DefineConstants>
        <ErrorReport>prompt</ErrorReport>
        <WarningLevel>4</WarningLevel>
      </PropertyGroup>
      <ItemGroup>
        <Reference Include="System" />
        <Reference Include="System.Core">
          <RequiredTargetFramework>3.5</RequiredTargetFramework>
        </Reference>
        <Reference Include="System.Xml.Linq">
          <RequiredTargetFramework>3.5</RequiredTargetFramework>
        </Reference>
        <Reference Include="System.Data.DataSetExtensions">
          <RequiredTargetFramework>3.5</RequiredTargetFramework>
        </Reference>
        <Reference Include="System.Data" />
        <Reference Include="System.Xml" />
      </ItemGroup>
      <ItemGroup>
        <Compile Include="Program.cs" />
        <Compile Include="Properties\AssemblyInfo.cs" />
      </ItemGroup>
      <Import Project="$(MSBuildToolsPath)\Microsoft.CSharp.targets" />
      <!-- To modify your build process, add your task inside one of the targets below and uncomment it. 
           Other similar extension points exist, see Microsoft.Common.targets.
      <Target Name="BeforeBuild">
      </Target>
      <Target Name="AfterBuild">
      </Target>
      -->
    </Project>
    


  • Naja wenn du IMMER vom ROOT Objekt die ChildNodes abfragst, wird die Rekursion nur bis zur 1. Ebene übernommen... wäre jetzt so der Punkt auf den ich zu erst mit dem nackten Finger zeugen würde.



  • Hehe natürlich ich vergass das Problem. Ich trottel. Das Problem ist folgendes, die Struktur wie sie in der XML-Besteht wird nich im Treeview aufgebaut. Der Treeview hat auschließlich 1 Element und in diesem stehen dann alle Daten aus der XML drinne.Das ist aber nicht das ziel, ziel soll sein, dieselbe Baumstruktur wie sie in der XML besteht auf im Tree zu erstellen.



  • XmlElement root = doc.DocumentElement;
    treeView_xmltree.Nodes.Add(this.GetXmlAttributes(root,new TreeNode()));
    ...
    ...
    ...
    foreach (XmlNode daten in root.ChildNodes)
    

    Du gehst ja IMMER vom Root in die 1. Ebene, du solltest bei nachfolgenden GetXmlAttributes Aufruf auch die Ebene wechseln, damit die nächst tieferen Ebenen ausgelesen werden.



  • Nee mach ich nicht.Schau in die Methode welche die eigentliche Rekursion enthält.Da übergebe ich der GetXMLAttribute Funktion den aktuellen Knoten wo ich mich befinde und somit befinde ich mich in der nächsten Ebene.



  • Ich Vollhorst, ich hab einfach nur vergessen, einen neuen Node zu erstellen.

    So klappts:

    private TreeNode GetXmlAttributes(XmlNode root,TreeNode n)
            {   
    
                foreach (XmlNode daten in root.ChildNodes)
                {
                    TreeNode newnode = n.Nodes.Add(daten.Name);
                    this.GetXmlAttributes(daten, newnode);
                }
                return n;
            }
    

    🙄 Über mich selbst



  • und dann noch in einer viewmodelverpacken:

    view:

    <TreeView ItemsSource="{Binding DocumentTree}">
        <TreeView.ItemTemplate>
            <HierarchicalDataTemplate ItemsSource="{Binding Path=Items}">
                <TextBlock Text="{Binding Name}" />
            </HierarchicalDataTemplate>
        </TreeView.ItemTemplate>
    </TreeView>
    

    viewmodel:

    // helper
    public class Item
    {
        public Item()
        {
            Items = new ObservableCollection<Item>();
        }
        public string Name { get; set; }
        public ObservableCollection<Item> Items { get; set; }
    }
    
    //viewmodel
    public ObservableCollection<Item> DocumentTree { get; set; }
    public Window1ViewModel()
    {
        DocumentTree = new ObservableCollection<Item>();
        XmlDocument document = new XmlDocument();
        document.Load("D:\\XmlDemoFile.xml");
        Item item = new Item();
        LoadNode(item, document.DocumentElement);
        DocumentTree.Add(item);
    }
    
    private void LoadNode(Item parent, XmlNode root)
    {
        foreach(XmlNode childNode in root.ChildNodes)
        {
            parent.Name = childNode.Name;
            if (childNode.HasChildNodes)
            {
                Item childItem = new Item();
                LoadNode(childItem, childNode);
                parent.Items.Add(childItem);
            }
        }
    }
    

    natuerlich ist das nur ein dummy und zeigt nur den namen der nodes - nun kann man "Item" noch um attribute usw erweitern, und es dann im DataTemplate schick anzeigen lassen {=
    uuuuuuund man hat gleich ein baum mit den man arbeiten koennte #gg

    //dazuedit - ich sollte noch erwaehnen das der eben gezeigte code im kopf entstand - komplett ungetestet {o;



  • :p danke für den WPF-Code 😃 Aber meins war für eine normale Formsanwendung.
    Aber wo du es grad sagst, kann ich das auch gleich auf WPF umbauen 😃



  • Hmm ich hab das mal bissel umgebaut das Beispiel von dir.Laden tut er aber die XML nicht in den TreeView.
    Was ich noch fragen wollte, was ist denn das für eine Funktion bei dir hier, die Window1ViewModel? Ist das nen Event? oder was für ne bedeutung hat die, weil ich hab den code aus der Funktion jetzt in dem Loaded Event drinne.



  • meeeep - das gibt punkt abzug - 3 runden laufen q:

    hatte es nur aus faulheit zusammen getickert
    Window1ViewModel ist eine klasse die im DataContext der View liegt {o; => MVVM

    am ende sieht die solution ungefaer so aus:

    app.cs

    protected override OnStartUp()
    {
        Window1 view = new Window1();
        view.DataContext = new Window1ViewModel();
        view.Show();
        base.OnStartUp();
    }
    

    window1.xaml

    <Window ...>
        <TreeView ItemsSource="{Binding DocumentTree}">
            <TreeView.ItemTemplate>
                <HierarchicalDataTemplate ItemsSource="{Binding Path=Items}">
                    <TextBlock Text="{Binding Name}" />
                </HierarchicalDataTemplate>
            </TreeView.ItemTemplate>
        </TreeView>
    </Window>
    

    Window1ViewModel.cs

    public class Window1ViewModel
    {
        public ObservableCollection<Item> DocumentTree { get; set; }
        public Window1ViewModel()
        {
            DocumentTree = new ObservableCollection<Item>();
            XmlDocument document = new XmlDocument();
            document.Load("D:\\XmlDemoFile.xml");
            Item item = new Item();
            LoadNode(item, document.DocumentElement);
            DocumentTree.Add(item);
        }
    
        private void LoadNode(Item parent, XmlNode root)
        {
            foreach(XmlNode childNode in root.ChildNodes)
            {
                parent.Name = childNode.Name;
                if (childNode.HasChildNodes)
                {
                    Item childItem = new Item();
                    LoadNode(childItem, childNode);
                    parent.Items.Add(childItem);
                }
            }
        }
    }
    

    Item.cs

    public class Item
    {
        public Item()
        {
            Items = new ObservableCollection<Item>();
        }
        public string Name { get; set; }
        public ObservableCollection<Item> Items { get; set; }
    }
    


  • Ahh ok nun ergibt das Sinn. Man dein WPF-wissen ist ziemlich weitreichend. Machste das beruflich?Weil ick mache nur normales .NET beruflich und WPF immermal privat:)



  • danke fuer die blumen
    wpf mach ich auch beruflich ja (wobei ich nicht dazu verpflichtet bin), wir vertreiben bereits produkte welche in wpf entstanden
    wobei ich diese produkte nicht wiederrum mit mache - ich entwickel nur interne tools und framework issues (zb lokalisierungs base classes usw)

    privat mach ichs allerdings auch

    das was ich mir noch vorstellen koennte waere das man mit XPath die datei komplett in xaml auslesen und fuellen koennte - aber hab mit xpath noch keine erfahrung - drum wuerd ich das per code machen (dan hat man wenigstens auch ne arbeits grundlage #gg)

    was ich mir ausserdem noch vorstellen kann ist das man das datatemplate anpasst und zb diverse sachen farblich hervor zu heben, oder solche spielereien {=



  • Ja da haste Recht.Den Möglichkeiten ist ja keine Grenzen gesetzt 😃 Was mir jetzt aber noch fehlt, wäre das mein Stackpanel bzw der TreeView automatisch ein autoverticalscroll einrichtet wenn er sich zu groß expanded hat.
    Achja was mir auch aufgefallen ist, wenn ich die anwendung starte wird das hautpfenster doppelt geöffnet 😃 einmal mit inhalt und einmal ohne.



  • Firefighter schrieb:

    Ja da haste Recht.Den Möglichkeiten ist ja keine Grenzen gesetzt 😃 Was mir jetzt aber noch fehlt, wäre das mein Stackpanel bzw der TreeView automatisch ein autoverticalscroll einrichtet wenn er sich zu groß expanded hat.

    warum nicht n scrollviewer?

    <ScrollView VerticalScrollBarVisibility="Auto" HorizontalScrollBarVisibility="Auto">
        <TreeView ...>
    </ScrollView>
    

    Firefighter schrieb:

    Achja was mir auch aufgefallen ist, wenn ich die anwendung starte wird das hautpfenster doppelt geöffnet 😃 einmal mit inhalt und einmal ohne.

    du musst in der app.xaml noch die StartupUri raus schmeissen

    //dazuedit
    ich hoffe dir ist bewusst das du mit mvvm einiges umdenken musst {o;



  • Ja klar an den Scrollviewer hab ich gar nicht gedacht.Gibt einfach zu viel sachen mit denen man sein Ziel erreichen kann 😃
    Achja mir ist noch ein größeres Problem aufgefallen.Die Rekursion stimmt nicht 😃 Er nimmt immer nur die Letzten Elemente jedes Zweiges 😃



  • oh - hehe - ja
    dann baus um q: hast doch schon eine funktionierende rekursion da, nur anstatt direkt ein node zu erzeugen nimmst du halt Item und feddich #gg



  • Jop bin ick ja schon dabei 😉 danke nochmal.


Anmelden zum Antworten