How to build multi level hierarchy with unknown levels?

9 posts, 0 answers
  1. Robert
    Robert avatar
    271 posts
    Member since:
    Mar 2011

    Posted 22 Apr 2012 Link to this post

    Hi,

    I'm having difficulty trying to build a multi level hierarchy that has unknown levels.
    I've read loads and loads of examples but they all assume the number of levels are known. However, in my case I may have "x" number of nodes, which may have "x" number of child nodes, which may have "x" number of grandchild nodes etc etc.

    My data is drawn from an SQL database where I use the SQL 2008 HierarchyID data type to represent my hierarchy in the database.

    I've built the following class for my products:



    public class Products : INotifyPropertyChanged, IDataErrorInfo
    {
    private Int64 m_ID;
    private SqlHierarchyId m_Hierarchy;
    private string m_Name;
    private Int16 m_Level;
    private ObservableCollection<Products> m_ChildProducts;
    // Default Constructor
    public Products()
    {
    ChildProducts = new ObservableCollection<Products>();
    }
    //Properties
    public Int64 ID
    {
    get
    {
    return m_ID;
    }
    set
    {
    m_ID = value;
    OnPropertyChanged(new PropertyChangedEventArgs("ID"));
    }
    }
    public SqlHierarchyId Hierarchy
    {
    get
    {
    return m_Hierarchy;
    }
    set
    {
    m_Hierarchy = value;
    OnPropertyChanged(new PropertyChangedEventArgs("Hierarchy"));
    }
    }
    public Int16 Level
    {
    get
    {
    return m_Level;
    }
    set
    {
    m_Level = value;
    OnPropertyChanged(new PropertyChangedEventArgs("Level"));
    }
    }
    public String Name
    {
    get
    {
    return m_Name;
    }
    set
    {
    m_Name = value;
    OnPropertyChanged(new PropertyChangedEventArgs("Name"));
    }
    }
    public ObservableCollection<Products> ChildProducts
    {
    get
    {
    return m_ChildProducts;
    }
    set
    {
    m_ChildProducts = value;
    OnPropertyChanged(new PropertyChangedEventArgs("ChildProducts"));
    }
    }
    //INotifyPropertyChanged Event
    public event PropertyChangedEventHandler PropertyChanged;
    public void OnPropertyChanged(PropertyChangedEventArgs e)
    {
    if (PropertyChanged != null)
    PropertyChanged(this, e);
    }
    }


    I then have the following method to download data from the database which I need to some how construct an ObservableCollection() which contains nodes "x" number of levels deep. Please note that some nodes may be 2 levels deep, others may be 3 levels deep, so forth and so forth.


    public static ObservableCollection<Products> GetProductsHierarchy()
            {
                ObservableCollection<Products> products = new ObservableCollection<Products>();
     
                SqlConnection connection = new SqlConnection(DBConnection.GetConnection().ConnectionString);
     
                string selectStatement = "SELECT ID, Hierarchy, Name " +
                                         "FROM SpecProducts " +
                                         "WHERE (EnableDisable IS NULL)" +
                                         "ORDER BY Hierarchy";
     
                SqlCommand selectCommand = new SqlCommand(selectStatement, connection);
     
                try
                {
                    connection.Open();
                    SqlDataReader reader = selectCommand.ExecuteReader();
     
                    while (reader.Read())
                    {
                         
                        Products product = new Products();
                        product.ID = (Int64)reader["ID"];
                        product.Name = reader["Name"].ToString();
                        product.Hierarchy = (SqlHierarchyId)reader["Hierarchy"];
                        product.Level = (Int16)product.Hierarchy.GetLevel();
     
                        //**** How to create recursive loop to add unknown levels to nodes???? ****
     
                        products.Add(product);
                    }
     
     
                    return products;
                }
                catch (SqlException ex)
                {
                    throw ex;
                }
                finally
                {
                    connection.Close();
                }
            }


    I've found a post that discusses unlimited nodes, http://www.telerik.com/community/forums/wpf/treeview/templated-node-multiple-parent.aspx , but in the example given it has the following lines of code to build up unlimited levels:
    ObservableCollection<Node> nodes = new ObservableCollection<Node>();
     
    nodes.Add(new Node("Company"));
    nodes[0].Nodes.Add(new Node("Department"));
    nodes[0].Nodes[0].Nodes.Add(new Node("here are you"));
    nodes[0].Nodes[0].Nodes[0].Nodes.Add(new Node("even deeper"));
     
    radTreeView1.ItemsSource = nodes;

    Surely this is only valid providing you know the number of levels before runtime?


    I guess I'm essentially looking for a generic hierarchy builder where the number of levels are unknown until runtime, i.e. when data is download from database.

    Any help would be greatly appreciated.

    Thanks for your time.


  2. Petar Mladenov
    Admin
    Petar Mladenov avatar
    2891 posts

    Posted 25 Apr 2012 Link to this post

    Hi Robert,

     The way to prepare your RadTreeView for unknown hierarchy levels is to prepare well your ViewModels. If your DB objects cannot satisfy the following requirements, you can create a ViewModel wrapper classes to wrap your DB entities.
    So if your ViewModels have child Collection called "Children" and you want common Template you just have to use one HierarchicalDatatemplate definition:

    <telerik:HierarchicalDataTemplate x:Key="itemtemplate" ItemsSource="{Binding Children}">
                    <TextBlock Text="{Binding Name}"  />
    </telerik:HierarchicalDataTemplate>
    <telerik:RadTreeView ItemTemplate="{StaticReSource itemtemplate}" ...
    This way you can have unknown number of hierarchy levels. Every level will automatically use this template and will provide "Children" child collection.
    If your ViewModels are different types you have to make them inherit from one base type and use TemplateSelectors - if A item is given - use ATemplate, if B item is given - use BTemplate but A and B must inherit from one base type. You can check the attached project where similar approach is realized.
    (It is an SL solution, but the same technique could be used for WPF).
    Please let us know if you need further assistance on this. Regards,
    Petar Mladenov
    the Telerik team

    Explore the entire Telerik portfolio by downloading the Ultimate Collection trial package. Get it now >>

  3. UI for WPF is Visual Studio 2017 Ready
  4. Robert
    Robert avatar
    271 posts
    Member since:
    Mar 2011

    Posted 25 Apr 2012 Link to this post

    Hi,

    thank you for your response. For some reason I am unable to download your zip file example. When I click the download link I'm presented with a blank screen and nothing happens.
  5. Petar Mladenov
    Admin
    Petar Mladenov avatar
    2891 posts

    Posted 26 Apr 2012 Link to this post

    Hi Robert,

    I am attaching the file again. Could you please try to download it again? If the issue is still reproducible, could you please test this with different browsers ? Is it possible for you to send us a captured video ? Thank you in advance.

    Kind regards,
    Petar Mladenov
    the Telerik team

    Explore the entire Telerik portfolio by downloading the Ultimate Collection trial package. Get it now >>

  6. Robert
    Robert avatar
    271 posts
    Member since:
    Mar 2011

    Posted 26 Apr 2012 Link to this post

    Hi,

    Thanks for trying to repost it. Unfortunately this link also doesn't work.
    I've tried it with IE9 32bit & 64bit browsers. I currently don't have another browser installed on my PC. I will have to try someone elses computer when I get a chance and I don't have any screen capture software. Can you recommend any screen capture packages?
  7. Robert
    Robert avatar
    271 posts
    Member since:
    Mar 2011

    Posted 26 Apr 2012 Link to this post

    Here's a more in depth forum post to my problem http://stackoverflow.com/questions/10300273/how-to-build-object-hierarchy-from-sql-query-for-wpf-treeview

    However this isn't the complete solution. For some reason it only works to two node levels deep.
  8. Robert
    Robert avatar
    271 posts
    Member since:
    Mar 2011

    Posted 26 Apr 2012 Link to this post

    I've uploaded my treeview code project to the internet. It only contains the treeview code.
    Can someone please take a look at it for me? For some reason it will only generate nodes 2 levels deep.
    You can see how it works by looking at the MainWindow Loadoad Method.
    This is WPF c# .net 4 with the latest telerik libraries.

    Click here to download the file

    Thank you very much for your time. All help is appreciated.
  9. Robert
    Robert avatar
    271 posts
    Member since:
    Mar 2011

    Posted 26 Apr 2012 Link to this post

    I have managed to solve it but programmatically, i.e. not via binding.

    You can download my source code here.

    I'm still all ears if someone can find a solution using bindings for my example.
  10. Petar Mladenov
    Admin
    Petar Mladenov avatar
    2891 posts

    Posted 27 Apr 2012 Link to this post

    Hi Robert,

     Similar project to the one I attached here is also attached in this forum post. You can also check a good "TreeView bound to self-referencing table" Solution in this thread. Hope you will find them useful.

    Kind regards,
    Petar Mladenov
    the Telerik team

    Explore the entire Telerik portfolio by downloading the Ultimate Collection trial package. Get it now >>

Back to Top
UI for WPF is Visual Studio 2017 Ready