This is a migrated thread and some comments may be shown as answers.

How to populate Treeview using XML structure

5 Answers 668 Views
TreeView
This is a migrated thread and some comments may be shown as answers.
Rajesh
Top achievements
Rank 1
Rajesh asked on 05 Feb 2013, 06:50 AM

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.

 

5 Answers, 1 is accepted

Sort by
0
Rajesh
Top achievements
Rank 1
answered on 06 Feb 2013, 05:08 AM
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
0
Tina Stancheva
Telerik team
answered on 06 Feb 2013, 12:02 PM
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.

0
Rajesh
Top achievements
Rank 1
answered on 06 Feb 2013, 04:40 PM
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


0
Accepted
Tina Stancheva
Telerik team
answered on 11 Feb 2013, 03:12 PM
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.

0
Rajesh
Top achievements
Rank 1
answered on 15 Feb 2013, 06:40 AM
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);
            }
        }

Tags
TreeView
Asked by
Rajesh
Top achievements
Rank 1
Answers by
Rajesh
Top achievements
Rank 1
Tina Stancheva
Telerik team
Share this question
or