Extending the RadTreeView pt1

Thread is closed for posting
4 posts, 0 answers
  1. CE8FD5B8-D57F-4131-8A9A-47DA58D4A301
    CE8FD5B8-D57F-4131-8A9A-47DA58D4A301 avatar
    1622 posts
    Member since:
    Jul 2004

    Posted 02 Oct 2009 Link to this post

    Requirements

    RadControls version

    All AJAX versions
    .NET version

    v2.0 (I think) v3+
    Visual Studio version

    Only tried in VS2k8
    programming language

    C#
    browser support

    all browsers supported by RadControls


    PROJECT DESCRIPTION
    I have, over the past couple of weeks, found myself writing the same, or similar code over and again. Particularly, I've been writing code to do searches of the RadTreeView starting a any given level, some times searching all of a node's dependants, sometimes, just the child nodes of that node.

    Being basically a lazy guy, I decided to write a couple of extensions I could use in my programming without having to go through all the hassle of sub-classing this or that telerik control class.

    The following shows a couple of extensions that allow you to:
    • do a generic search of all dependent nodes of a given node or treeview;
    • sort the nodes collection of a treeview or tree node and, if required, apply that sort method recursively through all dependent nodes of the start point.

    Let's look at the 'FindNodes' extension method first.

    The signatures for the 2 FindNodes overloads look like this:
    List<RadTreeNode> FindNodes(IRadTreeNodeContainer source, Predicate<RadTreeNode> predicate); 
    List<RadTreeNode> FindNodes(IRadTreeNodeContainer source, Predicate<RadTreeNode> predicate, bool Deep) 

    I have no doubt that the majority of readers can tell me more about generic types and methods applying to them than I could hope to know, so I'll keep this brief.

    The first of these 2 overloads limits the search to the immediate children the treeview or node it is applied to, the second acts recursively through all the dependent child nodes of the starting point if the Deep parameter is true.

    Because the method use Predicate<RadTreeNode> the search criterion can be as complex as you need it to be. If the code is using C# v3 or later it can also be written using lambda notation. So, it is possible to search using code like this...
    // A deliberately silly lambda expression used to find nodes 
    List<RadTreeNode> hits = RadTreeView1.FindNodes(n => n.Category == "SomeValue" && Convert.ToInt32(n.Value) > 3 || String.IsNullOrEmpty(n.Attributes["MyAtt"])); 

    or, if you have something a little trickier ...
    static bool MyNodeSearch(RadTreeNode Node) { 
      // some cunningly clever code goes here and returns true or false 
      return true
     
    // later ... 
     
    List<RadTreeNode> hits = RadTreeView1.Nodes[0].FindNodes(MyNodeSearch, true); 

    I'm sure you've work all this by now, so I'll shut up.

    Next is the 'SortNodes' method which, if I'm honest, is based on a forum post by someone at telerik towers.

    Again, there are 2 overloads and, again, one operates on just the Nodes collection of the start node or treeview and the other operates recursively. The signatures look like this...
    SortNodes(IRadTreeNodeContainer parentNode, Comparison<RadTreeNode> comparison) 
    SortNodes(IRadTreeNodeContainer parentNode, Comparison<RadTreeNode> comparison, bool Deep) 

    Once again, you can use anonymous delegates or lambda expressions for the Comparison<T>.

    Incidentally, for those of you who haven't picked up on it, both methods described here can be used against RadTreeViews or RadTreeNodes because the first argument is of type IRadTreeNodeContainer.

    So, I guess you want to see the code. If you have lots of projects that you use RadContols in, you might want to compile the extensions up in to a separate Library assembly that you can reuse.

    Anyway, here's the code. I hope you find it useful.
      public static class Extensions { 
        public static List<RadTreeNode> FindNodes(this IRadTreeNodeContainer source, Predicate<RadTreeNode> predicate) { 
          return source.FindNodes(predicate, false); 
        } 
     
        public static List<RadTreeNode> FindNodes(this IRadTreeNodeContainer source, Predicate<RadTreeNode> predicate, bool Deep) { 
          List<RadTreeNode> result = new List<RadTreeNode>(); 
          foreach(RadTreeNode node in source.Nodes) { 
            if(predicate(node)) 
              result.Add(node); 
            if(Deep && node.Nodes.Count > 0) { 
              result.AddRange(node.FindNodes(predicate, Deep)); 
            } 
          } 
          return result; 
        } 
     
        public static void SortNodes(this IRadTreeNodeContainer parentNode, Comparison<RadTreeNode> comparison) { 
          parentNode.SortNodes(comparison, false); 
        } 
         
        public static void SortNodes(this IRadTreeNodeContainer parentNode, Comparison<RadTreeNode> comparison, bool Deep) { 
          List<RadTreeNode> nodes = new List<RadTreeNode>(parentNode.Nodes.Count); 
     
          foreach(RadTreeNode node in parentNode.Nodes) { 
            if(Deep && node.Nodes.Count> 1) 
              node.SortNodes(comparison, Deep); 
             
            nodes.Add(node); 
          } 
     
          nodes.Sort(comparison); 
          parentNode.Nodes.Clear(); 
          parentNode.Nodes.AddRange(nodes); 
        }  
      } 
     

    Next time, I'll be showing a neat (I think) extension I use when using the treeview as a navigation control.

    --
    Stuart





  2. 24C14283-7B95-488B-95A6-4C6E9045F9C1
    24C14283-7B95-488B-95A6-4C6E9045F9C1 avatar
    1 posts
    Member since:
    Jan 2011

    Posted 24 Jan 2011 Link to this post

    Stuart,
    I am trying to use a tree view control to view config file key value pairs.    I've used a XML data source to load the control and set the xpath property to "/Configuration".    It loads well except when it gets to the <add key="" value""/> .  Of course the control doesn't understand how to interpret the "add" node.   How would I change that?

        eg. 
            Web.config: Configuration    
                                    |-----------> AppSettings
                                    |        |-----------------------> key:  value
                                    |-----------> Connection Strings
                                    |        |-----------------------> key: value


    JG.
  3. CE8FD5B8-D57F-4131-8A9A-47DA58D4A301
    CE8FD5B8-D57F-4131-8A9A-47DA58D4A301 avatar
    1622 posts
    Member since:
    Jul 2004

    Posted 24 Jan 2011 Link to this post

    Mardi,

    To be honest, I'm not sure that you can.

    I think I'd've been more tempted to loop through the XML file, creating a simple object to represent each element and use a list of those objects to populate the tree.

    -- 
    Stuart
  4. CE8FD5B8-D57F-4131-8A9A-47DA58D4A301
    CE8FD5B8-D57F-4131-8A9A-47DA58D4A301 avatar
    1622 posts
    Member since:
    Jul 2004

    Posted 24 Jan 2011 Link to this post

    Actually,

    Thinking a little more about it, if you handled the NodeDataBound event, you could grab the DataItem and set the text/value to anything you please, I suppose.

    You'd need to test for the variations in data from the different bits of the XML file's structure, I suppose but...

    -- 
    Stuart
Back to Top

This Code Library is part of the product documentation and subject to the respective product license agreement.