PanelBar, TreeView, and XmlHttpPanel

6 posts, 1 answers
  1. Neil
    Neil avatar
    16 posts
    Member since:
    Mar 2007

    Posted 24 Nov 2010 Link to this post

    The page has a panel bar which dynamically loads TreeViews as PanelItems.  To prevent losing the trees during a postback, a custom control is loaded in the XmlHttpPanel.  In order to get the correct control and pass all desired information, I need to access multiple custom attributes of the selected node.  Any suggestions on how to either pass or access the selected node server side (from within the "XmlHttpPanel_ServiceRequest" without performing a postback? 

    Update to post: The trees are gone upon the service request as well and since the tree and nodes or not serializable the information cannot be stored in the viewstate either.  What was the point of making a control that loses its contents upon a postback?  Looks like the path will be to stuff everything into a long string for use as the "value" on the service call then parse out what's needed.  For such an impressive toolset overall, seems like the PanelBar is a tad lacking.  Unless of course, I missing the obvious which is always a possibility.

    Below is an overly simplified view of what is being attempted.

    <!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
      
    <head runat="server">
        <title></title>
        <telerik:RadScriptBlock ID="RadScriptBlock1" runat="server">
            <script language="javascript" type="text/javascript">
                function NodeClicked(sender, args) {
                    var node = args.get_node();
                    var panel = $find("<%= RadXmlHttpPanel1.ClientID %>");
                    panel.set_value(node.get_text());
                }
            </script>
        </telerik:RadScriptBlock>
    </head>
    <body>
        <form id="form1" runat="server">
        <telerik:RadScriptManager ID="RadScriptManager1" runat="server">
        </telerik:RadScriptManager>
        <table>
            <tr>
                <td>
                    <telerik:RadPanelBar ID="RadPanelBar1" runat="server">
                    </telerik:RadPanelBar>
                </td>
                <td>
                    <telerik:RadXmlHttpPanel ID="RadXmlHttpPanel1" runat="server" OnServiceRequest="XmlHttpPanel_ServiceRequest">
                    </telerik:RadXmlHttpPanel>
                </td>
            </tr>
        </table>
        </form>
    </body>
    </html>

    public partial class Default : System.Web.UI.Page
        {
            protected void Page_Load(object sender, EventArgs e)
            {
                if (!Page.IsPostBack)
                    LoadRootContent();
            }
            private void LoadRootContent()
            {
                RadPanelItem myPanelItem = new RadPanelItem("Item 1");
                RadTreeView myTreeView = new RadTreeView();
                myTreeView.OnClientNodeClicked = "NodeClicked";
                //Build a node
                RadTreeNode node1 = new RadTreeNode("TreeNode 1");
                node1.Category = "Customers";
                node1.Attributes.Add("CustomerID", "123");
                myTreeView.Nodes.Add(node1);
                //Build another node
                RadTreeNode node2 = new RadTreeNode("TreeNode 2");
                node2.Category = "Prospects";
                node2.Attributes.Add("ProspectID", "456");
                myTreeView.Nodes.Add(node2);
      
                //Add the tree to the PanelItem - this could happen more than once for each PanelItem
                myPanelItem.Controls.Add(myTreeView);
                //Add the item to the PanelBar - this would occur for multiple items
                RadPanelBar1.Items.Add(myPanelItem);
            }
            protected void XmlHttpPanel_ServiceRequest(object sender, RadXmlHttpPanelEventArgs e)
            {
                string val = e.Value;
                if (val == "TreeNode 1")
                {
                    RadXmlHttpPanel1.Controls.Add(LoadControl("Test1.ascx"));
                }
                if (val == "TreeNode 2")
                    RadXmlHttpPanel1.Controls.Add(LoadControl("Test2.ascx"));
      
            }
        }

    Any suggestions or thoughts are welcome.
    Thanks in advance.
  2. Neil
    Neil avatar
    16 posts
    Member since:
    Mar 2007

    Posted 24 Nov 2010 Link to this post

    After much foul language and fussing, I feel pretty sheepish about how easy the solution actually was.  Below is the code that works for anyone else's reference.

    <!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
      
    <head runat="server">
        <title></title>
        <telerik:RadScriptBlock ID="RadScriptBlock1" runat="server">
            <script language="javascript" type="text/javascript">
                function NodeClicked(sender, args) {
                    var node = args.get_node();
                    var panel = $find("<%= RadXmlHttpPanel1.ClientID %>");
                    var stringArray = node.get_attributes
                    panel.set_value(node.toJsonString());
                }
            </script>
        </telerik:RadScriptBlock>
    </head>
    <body>
        <form id="form1" runat="server">
        <telerik:RadScriptManager ID="RadScriptManager1" runat="server">
        </telerik:RadScriptManager>
        <table>
            <tr>
                <td>
                    <telerik:RadPanelBar ID="RadPanelBar1" runat="server">
                    </telerik:RadPanelBar>
                </td>
                <td>
                    <telerik:RadXmlHttpPanel ID="RadXmlHttpPanel1" runat="server" OnServiceRequest="XmlHttpPanel_ServiceRequest">
                    </telerik:RadXmlHttpPanel>
                </td>
            </tr>
        </table>
        </form>
    </body>
    </html>

    protected void Page_Load(object sender, EventArgs e)
            {
                if (!Page.IsPostBack)
                    LoadRootContent();
            }
            private void LoadRootContent()
            {
                RadPanelItem myPanelItem = new RadPanelItem("Item 1");
                RadTreeView myTreeView = new RadTreeView();
                myTreeView.OnClientNodeClicked = "NodeClicked";
                //Build a node
                RadTreeNode node1 = new RadTreeNode("TreeNode 1");
                node1.Category = "Customers";
                node1.Attributes.Add("CustomerID", "123");
                myTreeView.Nodes.Add(node1);
                //Build another node
                RadTreeNode node2 = new RadTreeNode("TreeNode 2");
                node2.Category = "Prospects";
                node2.Attributes.Add("ProspectID", "456");
                myTreeView.Nodes.Add(node2);
      
                //Add the tree to the PanelItem - this could happen more than once for each PanelItem
                myPanelItem.Controls.Add(myTreeView);
                //Add the item to the PanelBar - this would occur for multiple items
                RadPanelBar1.Items.Add(myPanelItem);
                RadPanelBar1.EnableViewState = true;
            }
            protected void XmlHttpPanel_ServiceRequest(object sender, RadXmlHttpPanelEventArgs e)
            {
                System.Web.Script.Serialization.JavaScriptSerializer serializer = new System.Web.Script.Serialization.JavaScriptSerializer();
                RadTreeNode myNode = serializer.Deserialize<RadTreeNode>(e.Value);
      
                switch (myNode.Category)
                {
                    case "Customers":
                        RadXmlHttpPanel1.Controls.Add(LoadControl("Test1.ascx"));
                        break;
                    case "Prospects":
                        RadXmlHttpPanel1.Controls.Add(LoadControl("Test2.ascx"));
                        break;
                }
            }
  3. UI for ASP.NET Ajax is Ready for VS 2017
  4. Neil
    Neil avatar
    16 posts
    Member since:
    Mar 2007

    Posted 01 Dec 2010 Link to this post

    ok, so the RadTreeNode gets created but the attributes do not populate.  I'm guessing this is due to case sensitivity (just guessing after looking at the JSON string that gets generated.  It's the attributes that I really need.  Is there any one who can enlighten me?  Or am I going to have to parse the string myself and rebuild the node (or just use the data I recover)?
  5. Answer
    Pero
    Admin
    Pero avatar
    1156 posts

    Posted 02 Dec 2010 Link to this post

    Hello Dave,

    Apparently the JavaScriptSerializer does not correctly deserialize the Attributes collection object from the string provided. I tried capitalizing the first letter of "attributes" key, but again the Attributes did not get populated. So (I guess) the only way left is to manually populate the whole list.
    For your convenience I have modified your code to populate the collection manually. Here is the modified code:

    protected void XmlHttpPanel_ServiceRequest(object sender, RadXmlHttpPanelEventArgs e)
    {
        System.Web.Script.Serialization.JavaScriptSerializer serializer = new System.Web.Script.Serialization.JavaScriptSerializer();
        string value = e.Value;
     
        RadTreeNode myNode = serializer.Deserialize<RadTreeNode>(value);
     
        Dictionary<string, object> result = serializer.Deserialize<Dictionary<string, object>>(value);
        Dictionary<string, object> attributes = result["attributes"] as Dictionary<string, object>;
     
        foreach (string item in attributes.Keys)
        {
            myNode.Attributes.Add(item, attributes[item].ToString());
        }
     
        switch (myNode.Category)
        {
            case "Customers":
                int Checkit = myNode.Attributes.Count;
                RadXmlHttpPanel1.Controls.Add(new LiteralControl("Node 1 clicked:  " + result["attributes"]));
                break;
            case "Prospects":
                RadXmlHttpPanel1.Controls.Add(new LiteralControl("Node 2 clicked:  " + result["attributes"]));
                break;
        }
    }


    All the best,
    Pero
    the Telerik team
    Browse the vast support resources we have to jumpstart your development with RadControls for ASP.NET AJAX. See how to integrate our AJAX controls seamlessly in SharePoint 2007/2010 visiting our common SharePoint portal.
  6. Neil
    Neil avatar
    16 posts
    Member since:
    Mar 2007

    Posted 02 Dec 2010 Link to this post

    Thanks Pero, I had already created another method which is not as elegant as yours but will parse the JSON string without the need to bother with the deserialization.  I've included my code here for the convenience of others.  Also of note, do not assign a name of "ID" for an attribute as the JSON serialization process appears to strip that from the attributes list.  Make sure to append "ID" with something or use a different name all together.  It is important when manually parsing to leave the original string intact for the most part as there is no guarrantee that in future updates or calls the items contained in the string will be in the same order.  So mapping the original attributes of the object as well as any attribute which is actually an array is essential for continued success.

    public class radExtenders
    {
        public static RadTreeNode BuildNodeFromJSONstring(String myString)
        {
            RadTreeNode myNode = new RadTreeNode();
            //Get rid of Quotes
            myString = myString.Replace("\"", "");
            //Retrieve the original Node value
            int nodeValueStart = myString.IndexOf("value:");
            string myNodeString = myString.Remove(0, nodeValueStart + 6);
            int nodeValueEnd = myNodeString.IndexOf(",");
            myNode.Value = myNodeString.Substring(0, nodeValueEnd);
            //Retrieve category name
            int CategoryNameStart = myString.IndexOf("category:");
            string myCategoryString = myString.Remove(0, CategoryNameStart + 9);
            int CategoryNameEnd = myCategoryString.IndexOf(",");
            myNode.Category = myCategoryString.Substring(0, CategoryNameEnd);
            //Find then retrieve the attributes if any
            int AttribStart = myString.IndexOf("attributes:");
            if (AttribStart > -1)
            {
                string strAttribList = myString.Remove(0, AttribStart + 12);
                int AttribEnd = strAttribList.IndexOf("}");
                strAttribList = strAttribList.Substring(0, AttribEnd);
                while (strAttribList.Length > 0)
                {
                    int NameFinder = strAttribList.IndexOf(":");
                    string strName = strAttribList.Substring(0, NameFinder);
                    strAttribList = strAttribList.Remove(0, NameFinder + 1);
                    int ValueFinder = strAttribList.IndexOf(",");
                    string strValue = string.Empty;
                    if (ValueFinder > -1)
                    {
                        strValue = strAttribList.Substring(0, ValueFinder);
                        strAttribList = strAttribList.Remove(0, ValueFinder + 1);
                    }
                    else
                    {
                        strValue = strAttribList;
                        strAttribList = string.Empty;
                    }
                    myNode.Attributes.Add(strName, strValue);
                    //Remove after testing
                    if (strName == "ctgID")
                    {
                        string stopHere = "StopHere";
                    }
                }
            }
            //Find Text value for node
            int TextValueStart = myString.IndexOf("text:");
            string myTextString = myString.Remove(0, TextValueStart + 5);
            int TextValueEnd = myTextString.IndexOf(",");
            if (TextValueEnd > -1)
            {
                myNode.Text = myTextString.Substring(0, TextValueEnd);
            }
            else
            {
                myNode.Text = myTextString.Substring(0, myTextString.Length - 2);
            }
            return myNode;
        }
    }
  7. Pero
    Admin
    Pero avatar
    1156 posts

    Posted 07 Dec 2010 Link to this post

    Hello Dave,

    Thank you for the additional information!

    I will close this thread, and if you have other questions you can contact us at any time.

    Greetings,
    Pero
    the Telerik team
    Browse the vast support resources we have to jumpstart your development with RadControls for ASP.NET AJAX. See how to integrate our AJAX controls seamlessly in SharePoint 2007/2010 visiting our common SharePoint portal.
Back to Top
UI for ASP.NET Ajax is Ready for VS 2017