How to populate Treeview using XML structure

6 posts, 1 answers
  1. Rajesh
    Rajesh avatar
    15 posts
    Member since:
    Jan 2013

    Posted 05 Feb 2013 Link to this post

    Hi there,

      My customer would like to have new structure in telerik treeview using the given XML file.

    Can you provide me a sample data that will load this XML structure into telerik treeview using MVVM pattern please?

    I have attached my XML structure as a file (Xml_Structure.jpg). Please take a look at it. 

    Your help will keep our project going and be highly appreciated.

    Below is the output that customer expects (in "Format Code Block" section)

    Reorg_Workbook
        Header
        Guide
            Accounts
                InstructDialog
                    TopPart
                    BottomPart
            Offer_Information_
                Offer_Information
                Option_Information
                Offer_Restrictions

    These are the criteria on this project.

    1. Example that follow MVVM pattern please.

    2. Code should be generic. Customer said, that they would be able to run against any of their XML structure.

    3. (Though XML has _(underscore) in it. We would like to have without "_(Underscore)" on all Parent and Child nodes.

    4. On selecting the node, I should be able to retrieve the value of the <Pref> (may be on the selected event). By this way I will be sending instruction to server to fetch our file of that "ID" and "PrefUsage" combination.

     

  2. Rajesh
    Rajesh avatar
    15 posts
    Member since:
    Jan 2013

    Posted 05 Feb 2013 Link to this post

    Hi there,

      I have attempted few steps in generating treeview from the xml given by customer.

    But the problem is, I have used as many as "TreeveiwItem" object for every new child node. This doesn't solve my problem.
    If new nodes is added to the XML, then I need to once again create "TreeViewItem" object.

    I would like to add "TreeviewItem" in code behind.

    Please take a look at my attempt.

    Please suggest how I should achieve in getting the "TreeViewItem" added programatically.

    Your help is highly appreciated and thanks in advance.
    using System;
    using System.Collections.Generic;
    using System.Linq;
    using System.Net;
    using System.Windows;
    using System.Windows.Controls;
    using System.Windows.Documents;
    using System.Windows.Input;
    using System.Windows.Media;
    using System.Windows.Media.Animation;
    using System.Windows.Shapes;
    using Telerik.Windows.Controls;
    using System.Xml;
    using System.IO;
     
    namespace TreeviewUsingXml
    {
        public partial class MainPage : UserControl
        {
            String xmlString = @"<?xml version='1.0'?>       
    <Reorg_Workbook>
      <Accounts>
        <Pref Id='REORG.Accounts' PrefUsage='Grid' />
        <Pref Id='REORG.Accounts' PrefUsage='Data' />
        <Pref Id='REORG.Accounts' PrefUsage='HeaderFooter' />
        <InstructDialog>
          <TopPart>
            <Pref Id='REORG.InstructDialogHeader' PrefUsage='Data' />
            <Pref Id='REORG.InstructDialogGrid' PrefUsage='Grid' />
          </TopPart>
          <BottomPart>
            <Pref Id='REORG.InstructDialogReturnData' PrefUsage='Data' />
            <Pref Id='REORG.InstructDialogForm' PrefUsage='Data' />
            <Pref Id='REORG.InstructDialogForm' PrefUsage='HeaderFooter' />
          </BottomPart>
        </InstructDialog>
      </Accounts>
    </Reorg_Workbook>";
     
     
            public MainPage()
            {
                InitializeComponent();
     
                // Create an XmlReader
                XmlReaderSettings settings = new XmlReaderSettings();
                settings.ConformanceLevel = ConformanceLevel.Fragment;
                settings.IgnoreWhitespace = true;
     
                XmlReader reader = XmlReader.Create(new StringReader(xmlString), settings);
                 
                RadTreeViewItem _parentNode = new RadTreeViewItem();
                RadTreeViewItem _childNode = new RadTreeViewItem();
                RadTreeViewItem _childNode1 = new RadTreeViewItem();
                 
                 
                while (reader.Read())
                {
                    switch (reader.NodeType)
                    {
                        case XmlNodeType.Element:
                            if (reader.Depth == 0)
                            {
                                _parentNode.Header = reader.Name;
                                WkbLocation_RadTreeView.Items.Add(_parentNode);                           
                            }
                            else if (reader.Name == "Pref")
                            {
                                string strUsageType = reader.GetAttribute("PrefUsage");
                                switch (strUsageType)
                                {
                                    case "Data":
                                        _childNode1 = new RadTreeViewItem();
                                        _childNode1.Header = "Fields";
                                        _childNode.Items.Add(_childNode1);                                   
                                        break;
                                    case "Grid":
                                        break;
                                    case "HeaderFooter":
                                        _childNode1 = new RadTreeViewItem();
                                        _childNode1.Header = "Footers";
                                        _childNode.Items.Add(_childNode1);                                   
                                        break;
                                    default:
                                        break;
                                }
                            }
                            else
                            {
                                _childNode = new RadTreeViewItem();
                                _childNode.Header = reader.Name;
                                _parentNode.Items.Add(_childNode);
                            }
                            break;
                        case XmlNodeType.Text:
                            //output = reader.Name;
                            break;
                        case XmlNodeType.CDATA:
                            //output = reader.Name;
                            break;
                        case XmlNodeType.XmlDeclaration:
                        case XmlNodeType.ProcessingInstruction:
                            //output = reader.Name;
                            break;
                        case XmlNodeType.Comment:
                            //output = reader.Name;
                            break;
                        case XmlNodeType.EndElement:
                            //output = reader.Name;
                            break;
                    }
                }
     
              
            }
        }
    }


    Thanks,
    Rajesh.B
  3. DevCraft banner
  4. Tina Stancheva
    Admin
    Tina Stancheva avatar
    3298 posts

    Posted 06 Feb 2013 Link to this post

    Hello Rajesh,

    It is better to use an MVVM approach like the one demonstrated in this article. This approach allows you to read the xml file but wrap all data in business objects. The business objects are then displayed in the RadTreeView - the ItemTemplate property defines a HierarchicalDataTemplate that controls the way the business data is displayed in the Header of each RadTreeViewItem.

    In the ItemTemplate you can use a Converter to display the Headers with "_" as the converter will allow you to converter the original value to a new string that doesn't contain "_".

    Please examine the article and consider my suggestions and let me know if you have any troubles implementing them.

    All the best,
    Tina Stancheva
    the Telerik team

    Explore the entire Telerik portfolio by downloading Telerik DevCraft Ultimate.

  5. Rajesh
    Rajesh avatar
    15 posts
    Member since:
    Jan 2013

    Posted 06 Feb 2013 Link to this post

    Hi Tina,

    Thanks for your reply.

    Please consider my 2nd post.
    I did take a look at the article before I started my post. That article DO NOT solve my problem. Because,

    1. They use Hirerichale Data Template. - I do not want to use it.

    2. It uses "Items" as "ItemSource" and "Header" in XML which this is good only when you know that your XML structure will always be using "Items" node and "Header" as attribute.

    My XML structure will have different nodes for every XML structure.

    Please take a look at my 2nd post where I have attempted to get the nodes from XML and started to populate in Telerik treeview.
    But the problem is that, I am creating new "TreeViewItem" for each new child nodes. Creating 'New' will work only for this xml structure and my code will not be generic.

    What my customer expecting is,

     1. Given any XML structure the code should process the XML and populate it in treeview. (Just only in code behind).

    I have the start, but how do I create one TreeViewItem object and reuse them for all the nodes.

    How to avoid creating multiple TreeviewItem object?

               RadTreeViewItem _parentNode = new RadTreeViewItem();
                RadTreeViewItem _childNode = new RadTreeViewItem();
                RadTreeViewItem _childNode1 = new RadTreeViewItem(); 

    Your sample code on getting this would be much much helpful please.

    Thanks,
    Rajesh.B


  6. Answer
    Tina Stancheva
    Admin
    Tina Stancheva avatar
    3298 posts

    Posted 11 Feb 2013 Link to this post

    Hello Rajesh,

    Please accept my apology for the misunderstanding. I thought you'd like to take advantage of MVVM, which would require an approach using HierarchicalDataTemplates. Basically, if you need an MVVM approach you need to have in mind that its main purpose is to create ViewModels to wrap the business data and then entirely separate that logic from the views. This article can give you more details on the concept and implementation of MVVM. Also, please note that we strongly recommend using an MVVM approach to dynamically populate the RadTreeView.ItemsSource collection. This will make your application more flexible and will allow you to take full advantage of the RadTreeView virtualization (UI and Data virtualization) features to display large amounts of data without slowing down the performance of your app.

    Furthermore, if you descide to go with the MVVM approach and you also want to use a generic data class to describe your data, you can take a look at the suggestions described in this forum. Based on one of them I prepared a sample solution demonstrating how to use MVVM to populate the RadTreeView.ItemsSource with generic data. In the solution I used the same data type to describe the content of two different xml files. I also used the same HierarchicalDataTemplate for both RadTreeView controls as I want to demonstrate how you can use the same RadTreeView setup to display differently structured xml files. But, please note that you may have to customize the logic in the Converter classes to better fit your xml data.

    In case you still want to use a declaratively defined RadTreeView (adding RadTreeViewItems in code-behind), you will need to create custom parsing logic to use the xml to create a hierarchical RadTreeView, just like you tried (in the code snippet you posted). However, you can't reuse the same RadTreeViewItems for all xml files. You will have to clear the Items collection of the control and also clear all references of the RadTreeViewItems (_parentNode, _childNode,_childNode1 properties) to remove the previously created RadTreeViewItems and avoid leaks. Then you'll have to create a new Items collection with new RadTreeViewItems.

    Basically when you declaratively define a RadTreeView, it is quite static. You set-up all items, the hierarchical structure and the Headers. And as this structure is specifically designed to display a specif structure of items, you can't reuse it for another RadTreeView with differently structured data. And with that approach, you will have to create a new RadTreeView (or at least a RadTreeView with entirely new Items collection) for each xml file. And if you want to dynamically add newly added xml nodes, you'll need to somehow detect the xml file change and manually add items. But, if you use a MVVM approach, as soon as you change the collection of nodes in the generic ViewModel, the RadTreeView control will update its collection.

    I hope this information will help. But please let me know if I'm missing anything from yuor requirements.

    Regards,
    Tina Stancheva
    the Telerik team

    Explore the entire Telerik portfolio by downloading Telerik DevCraft Ultimate.

  7. Rajesh
    Rajesh avatar
    15 posts
    Member since:
    Jan 2013

    Posted 15 Feb 2013 Link to this post

    Hi Tina,

      First, sorry for the delay in getting back to your suggestion.

    Well, I did take a look at your sample project. But, this holds good for creating Template kind of treeview. What I envisioned was completely through code in the code behind of xaml.

    I did finally achieved what I want. And this is something that I achieved using "Recursive" method of adding the child node to the parent.
    This code will work fine for any given xml structure(structure in terms of our product) by the customer.

    Alright, but your suggestion really gave me idea to learn other things too. I have that in mind and will apply appropriately.

    I am pasting my code here for someone who really want's to populate treeview on code behind without declaring "TreeviewItem" object for each node. Which could be achieved by using "Recursive" method.

    Thanks a lot for your suggestion!!
    <telerik:RadTreeView x:Name="WkbLocation_RadTreeView" Selected="WkbLocation_RadTreeView_Selected" SelectionMode="Single"  IsSingleExpandPath="True"
                         VerticalAlignment="Stretch" ItemContainerStyle="{StaticResource RADTreeViewItemStyle}" ScrollViewer.VerticalScrollBarVisibility="Auto"/>
    private const string TREE_ITEM_STYLE = "RADTreeViewItemStyle";
     
            private void LoadTree(string xmlString)
            {
                if (string.IsNullOrEmpty(xmlString))
                {
                    WkbLocation_RadTreeView.Items.Clear();
                }
                else
                {
                    try
                    {
                        XDocument xDoc = XDocument.Parse(xmlString, LoadOptions.PreserveWhitespace);
     
                        XElement eleRoot = xDoc.Root;
     
                        RadTreeViewItem _parentNode = new RadTreeViewItem();
     
                        _parentNode.Header = GetHeaderText(eleRoot);
     
                        WkbLocation_RadTreeView.Items.Add(_parentNode);
     
                        AddChildNodes(_parentNode, eleRoot);
                    }
                    catch (Exception ex)
                    {
                        _logger.LogException("LoadTree", ex);
                    }
     
                }
            }
     
     
            private void AddChildNodes(RadTreeViewItem tviParent, XElement eleParent)
            {
                XNode nd = eleParent.FirstNode;
     
                while (nd != null)
                {
                    AddNode(tviParent, nd as XElement);
                    nd = nd.NextNode;
                }
            }
     
            private void AddNode(RadTreeViewItem tviParent, XElement eleToAdd)
            {
                try
                {
                    RadTreeViewItem tvi;
     
                    if (tviParent != null && eleToAdd != null)
                    {
                        if (eleToAdd.Name == XmlTags.PREFERNCE)
                        {
                            tvi = new PrefTreeItem(eleToAdd);
     
                            tvi.Style = (Style)this.Resources[TREE_ITEM_STYLE];
     
                            tviParent.Items.Add(tvi);
                        }
                        else
                        {
                            tvi = new RadTreeViewItem();
     
                            tvi.Header = GetHeaderText(eleToAdd);
     
                            tvi.Style = (Style)this.Resources[TREE_ITEM_STYLE];
                            tviParent.Items.Add(tvi);
     
                            AddChildNodes(tvi, eleToAdd);
                        }
                    }
                }
                catch (Exception ex)
                {
                    _logger.LogException("AddNode", ex);
                }
            }

Back to Top
DevCraft banner