How do I populate a TreeView (Windows Control) with an XmlDocument?

How do I populate a System.Windows.Controls.TreeView with an XmlDocument?
With the code below, I get the xml values concatenated and displayed in one TreeViewItem!

Thank you for your help.
string xmlStr = @"<?xml version=""1.0"" encoding=""utf-16""?>
<ExchangeInventory xmlns:xsi=""http://www.w3.org/2001/XMLSchema-instance"" xmlns:xsd=""http://www.w3.org/2001/XMLSchema"">
  <Mailboxes>
    <Mailbox>
      <MailboxName>First Last</MailboxName>
      <PrimaryEmailAddress>flast@adtest.it</PrimaryEmailAddress>
      <DisplayName>First Last</DisplayName>
      <MailboxGuid>9604d077-2d7f-4428-a843-cf71ed8cc9b6</MailboxGuid>
      <MailboxType>UserMailbox</MailboxType>
      <Database>TESTMB01\TESTSG0101\TESTMB0101</Database>
      <IssueWarningQuota>3MB</IssueWarningQuota>
      <ProhibitSendQuota>5MB</ProhibitSendQuota>
      <ProhibitSendReceiveQuota>6MB</ProhibitSendReceiveQuota>
      <Aliases>
        <string>SMTP:flast@adtest.it</string>
      </Aliases>
    </Mailbox>
  </Mailboxes>
</ExchangeInventory>";

XmlDocument xmlDoc = new XmlDocument();
xmlDoc.LoadXml(xmlStr);

TreeView_ServiceInventory.ItemsSource = xmlDoc; // ?? or
TreeView_ServiceInventory.ItemsSource = xmlDoc.DocumentElement; // ?? or
TreeView_ServiceInventory.Items.Add(xmlDoc); // ?? or
TreeView_ServiceInventory.Items.Add(xmlDoc.DocumentElement); // ??

Open in new window

surly83Asked:
Who is Participating?
I wear a lot of hats...

"The solutions and answers provided on Experts Exchange have been extremely helpful to me over the last few years. I wear a lot of hats - Developer, Database Administrator, Help Desk, etc., so I know a lot of things but not a lot about one thing. Experts Exchange gives me answers from people who do know a lot about one thing, in a easy to use platform." -Todd S.

nmarunCommented:
Just to clarify, you want to list all the 'nodes' of the xml in the TreeView. Is this right?
0
surly83Author Commented:
right.
0
mikebirtCommented:
Hi,

You could use recurrsion to parse your xml and populate the tree 'by hand'. I've attached a code example of this approach.

HTH

Mike
private void PopulateTree()
        {
            string xmlStr = @"<?xml version=""1.0"" encoding=""utf-16""?>
                                <ExchangeInventory xmlns:xsi=""http://www.w3.org/2001/XMLSchema-instance"" xmlns:xsd=""http://www.w3.org/2001/XMLSchema"">
                                  <Mailboxes>
                                    <Mailbox>
                                      <MailboxName>First Last</MailboxName>
                                      <PrimaryEmailAddress>flast@adtest.it</PrimaryEmailAddress>
                                      <DisplayName>First Last</DisplayName>
                                      <MailboxGuid>9604d077-2d7f-4428-a843-cf71ed8cc9b6</MailboxGuid>
                                      <MailboxType>UserMailbox</MailboxType>
                                      <Database>TESTMB01\TESTSG0101\TESTMB0101</Database>
                                      <IssueWarningQuota>3MB</IssueWarningQuota>
                                      <ProhibitSendQuota>5MB</ProhibitSendQuota>
                                      <ProhibitSendReceiveQuota>6MB</ProhibitSendReceiveQuota>
                                      <Aliases>
                                        <string>SMTP:flast@adtest.it</string>
                                      </Aliases>
                                    </Mailbox>
                                  </Mailboxes>
                                </ExchangeInventory>";

            XmlDocument xmlDoc = new XmlDocument();
            xmlDoc.LoadXml(xmlStr);

            TreeViewItem rootNode = new TreeViewItem() {Header = "Root" };

            TreeView_ServiceInventory.Items.Add(rootNode);
            BuildTree(rootNode, (XmlNode)xmlDoc.DocumentElement);
        }

        private void BuildTree(TreeViewItem node, XmlNode xml)
        {
            if (xml.HasChildNodes)
            {
                TreeViewItem levelNode = new TreeViewItem() { Header = xml.Name };
                node.Items.Add(levelNode);

                foreach (XmlNode childNode in xml.ChildNodes)
                {
                    BuildTree(levelNode, childNode);
                }
            }
            else
            {
                node.Header = node.Header + " = " + xml.Value;
            }
        }

Open in new window

0

Experts Exchange Solution brought to you by

Your issues matter to us.

Facing a tech roadblock? Get the help and guidance you need from experienced professionals who care. Ask your question anytime, anywhere, with no hassle.

Start your 7-day free trial
Exploring ASP.NET Core: Fundamentals

Learn to build web apps and services, IoT apps, and mobile backends by covering the fundamentals of ASP.NET Core and  exploring the core foundations for app libraries.

surly83Author Commented:
Thanks mike, but i'm sure there is a way to avoid having to do all that work... the data is already in xml, can't we just somehow assign it to the TreeView data source?
0
nmarunCommented:
Surly,

There's nothing automatic about XML or TreeView. You still need to tell the TreeView what part of the XML needs to be displayed in the view.

Personally, I'd go with what Mike has mentioned.

Arun
0
mikebirtCommented:
Hi,

I agree it feels slightly off beat to have to manually parse a data tree structure into a visual tree structure. I've looked into data binding on the tree structure, but i still get stuck as the Xml objects aren't quite what you need - which again doesn't feel right as WPF supports all sorts of binding approaches.

What i've come up with isn't working, however i'll share it with you on the off chance that you (or someone else), can complete it and fix what ever is not quite right. I don't have the time right now to keep on with this.

in terms of references for this, two i found useful are:
http://msdn.microsoft.com/en-us/library/system.windows.hierarchicaldatatemplate.aspx
http://msdn.microsoft.com/en-us/library/aa348824.aspx

I feel i should say again this isn't a complete solution here, it doesn't work and i'm not 100% the approach is correct. I'm only sharing it as an illustration of the binding direction you're looking for. Whether it's the right binding approach or not i can't confirm. Whilst i like you're approach of "doesn't seem right, there must be a better way...", i think on this occasion i would be included myself to stop searching for the binding approach and use the minimal code recurrsion i posted before - if that does the job of course.

HTH

Mike
<Window x:Class="WpfApplication1.Window1"
    xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
    xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
    xmlns:Xml="clr-namespace:System.Xml;assembly=System.Xml"
        xmlns:XmlLinq="clr-namespace:System.Xml.Linq;assembly=System.Xml.Linq"
    Title="Window1" Height="300" Width="300">

    <Window.Resources>
        <ObjectDataProvider ObjectType="{x:Type XmlLinq:XElement}"
                          MethodName="Elements" x:Key="getElements">
            <ObjectDataProvider.MethodParameters />
        </ObjectDataProvider>

        <HierarchicalDataTemplate DataType="{x:Type XmlLinq:XElement}" 
                                  ItemsSource="{Binding Source={StaticResource getElements}, BindsDirectlyToSource=true}">
            <TextBlock Text="{Binding Path=Name}"/>
        </HierarchicalDataTemplate>
    </Window.Resources>

    <DockPanel LastChildFill="True">
        <TreeView Background="LightGray">
            <TreeViewItem x:Name="tvi"
              ItemsSource="{Binding Path=Root}"
              Header="My Xml Data" />
        </TreeView>
    </DockPanel>

</Window>


c#

public Window1()
        {
            InitializeComponent();

            string xmlStr = @"<?xml version=""1.0"" encoding=""utf-16""?> 
                                <ExchangeInventory xmlns:xsi=""http://www.w3.org/2001/XMLSchema-instance"" xmlns:xsd=""http://www.w3.org/2001/XMLSchema""> 
                                  <Mailboxes> 
                                    <Mailbox> 
                                      <MailboxName>First Last</MailboxName> 
                                      <PrimaryEmailAddress>flast@adtest.it</PrimaryEmailAddress> 
                                      <DisplayName>First Last</DisplayName> 
                                      <MailboxGuid>9604d077-2d7f-4428-a843-cf71ed8cc9b6</MailboxGuid> 
                                      <MailboxType>UserMailbox</MailboxType> 
                                      <Database>TESTMB01\TESTSG0101\TESTMB0101</Database> 
                                      <IssueWarningQuota>3MB</IssueWarningQuota> 
                                      <ProhibitSendQuota>5MB</ProhibitSendQuota> 
                                      <ProhibitSendReceiveQuota>6MB</ProhibitSendReceiveQuota> 
                                      <Aliases> 
                                        <string>SMTP:flast@adtest.it</string> 
                                      </Aliases> 
                                    </Mailbox> 
                                  </Mailboxes> 
                                </ExchangeInventory>";

            XDocument xDoc = XDocument.Parse(xmlStr);
            root = xDoc.Root;
            tvi.DataContext = this;
        }
        private XElement root;
        public XElement Root
        {
            get
            {
                return root;
            }
        }

Open in new window

0
It's more than this solution.Get answers and train to solve all your tech problems - anytime, anywhere.Try it for free Edge Out The Competitionfor your dream job with proven skills and certifications.Get started today Stand Outas the employee with proven skills.Start learning today for free Move Your Career Forwardwith certification training in the latest technologies.Start your trial today
.NET Programming

From novice to tech pro — start learning today.