TreeView adapter problem

Rate It (1)

Last post 04-17-2008 10:51 AM by muybn. 20 replies.

Sort Posts:

  • TreeView adapter problem

    09-27-2006, 6:30 PM
    • Member
      25 point Member
    • brian.brown
    • Member since 09-27-2006, 5:45 PM
    • Posts 5

    Moderator.. this is for the 'CSS Friendly Control Adapter' forum.  I posted this earlier and it was posted to 'Master Pages, Themes and Navigation controls': http://forums.asp.net/thread/1411894.aspx

    I have discovered several problems with the treeview adapter.

    First, NodeCheckChanged event is refired for every node that is checked in every postback.  I created a fix that involves creating a postbackeventreference in the BuildItem method of the TreeViewAdapter.cs file:

                    if (((item.ShowCheckBox != null) && (item.ShowCheckBox.Value == true)) ||
                        (treeView.ShowCheckBoxes == TreeNodeTypes.All) ||
                        ((treeView.ShowCheckBoxes == TreeNodeTypes.Leaf) && (!IsExpandable(item))) ||
                        ((treeView.ShowCheckBoxes == TreeNodeTypes.Parent) && (IsExpandable(item))) ||
                        ((treeView.ShowCheckBoxes == TreeNodeTypes.Root) && (item.Depth == 0)))
                    {
                        writer.WriteBeginTag("input");
                        writer.WriteAttribute("type", "checkbox");
                        writer.WriteAttribute("id", treeView.ClientID + "n" + _checkboxIndex.ToString() + "CheckBox");
                        writer.WriteAttribute("name", treeView.UniqueID + "n" + _checkboxIndex.ToString() + "CheckBox");
                        if (item.Checked)
                        {
                            writer.WriteAttribute("checked", "checked");
                        }
                        // Add event for checkchanged
                        writer.WriteAttribute("onclick", Page.ClientScript.GetPostBackEventReference(treeView, "c" + (Page.Server.HtmlEncode(item.ValuePath)).Replace("/", "\\"), true));
                        writer.Write(HtmlTextWriter.SelfClosingTagEnd);
                        _checkboxIndex++;
                    }

     To capture the event, I added the following code to the RaisePostBackEvent:
     

    	if (eventArgument != null)
                    {
                        if (eventArgument.StartsWith("s") || eventArgument.StartsWith("e"))
                        {
                            string selectedNodeValuePath = eventArgument.Substring(1).Replace("\\", "/");
                            TreeNode selectedNode = treeView.FindNode(selectedNodeValuePath);
                            if (selectedNode != null)
                            {
                                bool bSelectedNodeChanged = selectedNode != treeView.SelectedNode;
                                selectedNode.Selected = true; // does not raise the SelectedNodeChanged event so we have to do it manually (below).
                                ExpandToSelectedNode();
                                if (eventArgument.StartsWith("e"))
                                {
                                    selectedNode.Expanded = true;
                                }
    
                                if (bSelectedNodeChanged)
                                {
                                    Extender.RaiseAdaptedEvent("SelectedNodeChanged", new EventArgs());
                                }
                            }
                        }
                        else if (eventArgument.StartsWith("p"))
                        {
                            string parentNodeValuePath = eventArgument.Substring(1).Replace("\\", "/");
                            TreeNode parentNode = treeView.FindNode(parentNodeValuePath);
                            if ((parentNode != null) && ((parentNode.ChildNodes == null) || (parentNode.ChildNodes.Count == 0)))
                            {
                                ExpandToNode(parentNode);
                                parentNode.Expanded = true; // Raises the TreeNodePopulate event
                            }
                        }
                        else if (eventArgument.StartsWith("c"))
                        {
                            string parentNodeValuePath = eventArgument.Substring(1).Replace("\\", "/");
                            TreeNode parentNode = treeView.FindNode(parentNodeValuePath);
                            if (parentNode != null)
                            {
                                Extender.RaiseAdaptedEvent("TreeNodeCheckChanged", new TreeNodeEventArgs(parentNode));
                            }
                        }

     I then commented out the the RaiseAdaptedEvent line in the UpdateCheckmarks method:
     
                            if (item.Checked != bIsNowChecked)
                            {
                                item.Checked = bIsNowChecked;
                                // Adding postback support for checkmarks
                                //Extender.RaiseAdaptedEvent("TreeNodeCheckChanged", new TreeNodeEventArgs(item));

                            }

     That line was the cause of the TreeNodeCheckChanged event firing for every checked node.

    The second problem I found is the TreeViewAdapter doesn't raise events properly if the treeview is in a webcontrol.  This is due to how the RaiseAdapterEvent was created.. 
     

            public void RaiseAdaptedEvent(string eventName, EventArgs e)
            {
                string attr = "OnAdapted" + eventName;
                if ((AdaptedControl != null) &&
                    (AdaptedControl.Attributes[attr] != null) &&
                    (AdaptedControl.Attributes[attr].Length > 0))
                {
                    string delegateName = AdaptedControl.Attributes[attr];
                    MethodInfo method = AdaptedControl.Page.GetType().GetMethod(delegateName);
                    if (method != null)
                    {
                        object[] args = new object[2];
                        args[0] = AdaptedControl;
                        args[1] = e;
                        method.Invoke(AdaptedControl.Page, args);
                    }
                }
            }
     The Page references cause the code to fail as the method delegate is in a control and not page.  I fixed this by changing the code to:
     
            public void RaiseAdaptedEvent(string eventName, EventArgs e)
            {
                string attr = "OnAdapted" + eventName;
                if ((AdaptedControl != null) &&
                    (AdaptedControl.Attributes[attr] != null) &&
                    (AdaptedControl.Attributes[attr].Length > 0))
                {
                    string delegateName = AdaptedControl.Attributes[attr];
                    MethodInfo method = AdaptedControl.Parent.GetType().GetMethod(delegateName);
                    if (method != null)
                    {
                        object[] args = new object[2];
                        args[0] = AdaptedControl;
                        args[1] = e;
                        method.Invoke(AdaptedControl.Parent, args);
                    }
                }
            }

     I did some basic testing and it looks like referencing the parent works a lot better than referencing the page.

    The last problem I have figured out yet..  but it is easy to reproduce.  I can't get nodes to expand in some of the demos.  For example go here:
    http://www.asp.net/CSSAdapters/TreeView.aspx
    Change the theme to 'Enhanced', then try to expand a node.  The nodes won't expand.

  • Re: TreeView adapter problem

    09-27-2006, 9:46 PM
    • Contributor
      3,298 point Contributor
    • Russ Helfand
    • Member since 09-14-2005, 6:22 PM
    • Groovybits.com
    • Posts 741

    Hi Brian,

    Wow, I can't wait to study your ideas in more detail.  I expect to do so tomorrow.

    Meanwhile, I wanted to immediately answer your question regarding the problem with expanding the tree in the Enhanced them in the demo page you mentioned, http://www.asp.net/CSSAdapters/TreeView.aspx.

    Yes, that's on my to-do list to fix.  The problem stems from the lack of position:relative in a few spots in the CSS for the TreeViewExample.css file in the Enhanced them folder... though it is actually more complicated then is sounds because you have to use great care when adding position:relative in that file!

    You actually CAN expand the nodes in the tree.  You need to move your cursor just slightly to the LEFT of the plus/minus sign on the expandable tree nodes.  Give it a try.

    I'll write back when I've studied your other comments more.  I'm already hip deep in TreeView adapter code as you may have noticed from previous postings.  Thanks for the contribution.

    Russ Helfand
    Groovybits.com
  • Re: TreeView adapter problem

    09-28-2006, 3:00 PM
    • Contributor
      3,298 point Contributor
    • Russ Helfand
    • Member since 09-14-2005, 6:22 PM
    • Groovybits.com
    • Posts 741

    ... more information about the problem expanding/contracting the tree nodes in the Enhanced sample page, http://www.asp.net/cssadapters/treeview.aspx

    There is a pretty simple fix for this.  I'm leaning towards using it in the next rev of the kit... unless I hear from people that there is a problem with it.

    1. Edit App_Themes\Enhanced\TreeViewExample.css.
    2. Find the 2 rules involving AspNet-TreeView-Collapse and AspNet-TreeView-Expand.
    3. To each of these 2 rules, add the following:
          font-family: Courier;
          font-size: xx-large;
          line-height: 20px;

    I've tested this fix in IE6, FF 1.5.0.7, Netscape Nav 8.1 and Opera 9.02. They all seem fine.

    I'm still planning on replying in more detail to Brian's original suggestions for enhancing/modifying/fixing the TreeView expander.  I just need a bit more time.  Regards,

    Russ Helfand
    Groovybits.com
  • Re: TreeView adapter problem

    09-28-2006, 4:33 PM
    • Contributor
      3,298 point Contributor
    • Russ Helfand
    • Member since 09-14-2005, 6:22 PM
    • Groovybits.com
    • Posts 741

    ... starting to now look into Brian's original suggestions for changes to the TreeView adapter.  I very much like the idea of using Parent rather than Page in the RaiseAdaptedEvent method.  I've already integrated that into the code for the next rev.  Good just, Brian, spotting that and coming up with a good fix.

    The issue concerning improper raising of the TreeNodeCheckChanged event is going to take a bit more thought.  I have no doubt that your proposed solution will work in some cases... but it is going to conflict with other improvements planned for the TreeView.  See, http://forums.asp.net/thread/1393678.aspx.  That thread involves improving the TreeView (in part, by using the client-side onclick event for the checkbox) to cascade checkbox settings up/down the tree.  So, I'd prefer to avoid setting the onclick handler on the client to handle the change event on the server.  Instead, I'd like to figure out how we can use (and perhaps add to) the viewstate info after postback to figure out what was and wasn't checked previously compared to what is and isn't checked upon postback in order to issue raise the events appropriately.

    Let me know what you think.  I'll post back here when I've got a more developed solution to propose to handle the TreeNodeCheckChanged problem.  Again, thanks for the Page v. Parent fix in RaiseAdaptedEvent. Regards,

    Russ Helfand
    Groovybits.com
  • Re: TreeView adapter problem

    09-28-2006, 4:45 PM
    • Contributor
      3,298 point Contributor
    • Russ Helfand
    • Member since 09-14-2005, 6:22 PM
    • Groovybits.com
    • Posts 741

    ... regarding the TreeNodeCheckedChanged event... Brian (and others who are running into this) it's very important that you review these notes, http://forums.asp.net/thread/1393604.aspx.

    You MUST use the implementation pattern suggested in those notes.  That is, if you are using the adapted TreeView you should be setting OnAdaptedTreeNodeCheckChanged in your <asp:TreeView>.  Do not try to use the normal OnTreeNodeCheckChanged attribute.

    Brian, were you aware of that?  I know that chunk of information is buried at the moment.  It will be made much more prominent in kit's real documentation in the next rev.  Sorry if you ran afoul of it.

    Russ Helfand
    Groovybits.com
  • Re: TreeView adapter problem

    10-06-2006, 4:16 PM
    • Member
      25 point Member
    • brian.brown
    • Member since 09-27-2006, 5:45 PM
    • Posts 5

    Right.. However removing the traditional OnTreeNodeCheckChanged attribute didn't keep the event from firing repeatedly for every checked node on every postback.  I was originally posting about 3 problems until I realized that you were NOT supposed to have the OnAdapted attributes AND the traditional attributes definied.

  • Re: TreeView adapter problem

    10-06-2006, 5:08 PM
    • Contributor
      3,298 point Contributor
    • Russ Helfand
    • Member since 09-14-2005, 6:22 PM
    • Groovybits.com
    • Posts 741

    Actually, I think I was wrong with my last comment.  Even if you have both OnTreeNodeCheckChanged and OnAdaptedTreeNodeCheckChanged (i.e., you have both the OnAdapted--- and the On--- version of the event handler) I don't think you should see them called in a duplicate fashion.  Only one or the other should be being called.

    I have been working on the TreeView adapter (for the next rev) a tremendous amount lately and have looked for this duplicate event invokation in the debugger, etc.  I don't see it with my files.

    Is there any way for you to create a very simple and complete test recipe that I can use to try to dup the problem here?

    Russ Helfand
    Groovybits.com
  • Re: TreeView adapter problem

    10-08-2006, 3:39 PM
    • Member
      25 point Member
    • brian.brown
    • Member since 09-27-2006, 5:45 PM
    • Posts 5

    It is very easy to reproduce the problem with the CheckChanged event firing for ever cheked node on every postback.  Just add a button to the WalkThru/CheckboxTreeView.aspx provided in the adapter downloads.  Check a couple of the nodes and click the button.  You will see the checkchanged event fire for each node that is checked.  The checked state is remembered after the postback.  Click the button again and the checkchanged event will fire again for each checked node even though their checked state was not changed.

  • Re: TreeView adapter problem

    10-08-2006, 6:45 PM
    • Contributor
      3,298 point Contributor
    • Russ Helfand
    • Member since 09-14-2005, 6:22 PM
    • Groovybits.com
    • Posts 741

    Just got back from the veggie garden and started digging into this... I have good news on several fronts.

    First, and most immediately, I was able to duplicate the problem using Brian's latest recipe.  The safest and most immediate fix for you is (happily) quite easy.  Go to this posting, http://forums.asp.net/1/1397908/ShowThread.aspx.  Locate my posting 09-12-2006, 5:33 PM.  Cut-n-paste the code I posted there to create a version of the TreeViewAdapter.cs file in your site's App_Code\Adapters.  (If you are using VB you may need to do a little conversion work.  There are some nice online converters but you still need to do some hand tweaking afterwards.  If you are using VB and are really stuck, let me know and I'll try to help.)

    Note that there are other ideas discussed on http://forums.asp.net/1/1397908/ShowThread.aspx that some of you might want to explore but getting them integrated isn't as easy as the simple cut-n-paste recipe I just offered.  Still, there are some great ideas there from others in the community.

    OK, the other piece of good news is that all of these fixes will be included in the next rev of the kit so what you're struggling with now won't last forever.  I apologize, though, for the immediate inconvenience. I'm working on other improvements to the TreeView adapter (like maintaining the true and complete expand/collapse state between postbacks) so your patience will be rewarded.

    If the fix at http://forums.asp.net/1/1397908/ShowThread.aspx does not solve your problem (i.e., if you continue to see events being fired inappropriately and too often) let me know.  My testing locally showed that applying the fix in http://forums.asp.net/1/1397908/ShowThread.aspx made this problem (which I could repro prior to applying the fix) go away.  If your results vary from that... let me know.

    Best regards,

    Russ Helfand
    Groovybits.com
  • Re: TreeView adapter problem

    07-10-2007, 4:43 PM
    • Member
      100 point Member
    • ahsteele
    • Member since 01-19-2007, 9:34 PM
    • Albuquerque, NM
    • Posts 112

    Russ I am having this exact problem.  In trying to fix it I attempted using your rewritten TreeViewAadapter from 09-12-2006, 5:33 PM to no avail.  I believe that I am using the most recent rev of the adapters but, more than likely I am missing something very simple here.  Any help would be greatly appreciated.

    Please remember to click “Mark as Answer” on the post that helps you, and to click “Unmark as Answer” if a marked post does not actually answer your question.
    This can be beneficial to other community members reading the thread.
  • Re: TreeView adapter problem

    07-10-2007, 4:56 PM
    • Member
      100 point Member
    • ahsteele
    • Member since 01-19-2007, 9:34 PM
    • Albuquerque, NM
    • Posts 112

    Wish I had noticed this before so I could have skipped the double post.  The code from the other thread also dumps the label association for the check boxes.

    Please remember to click “Mark as Answer” on the post that helps you, and to click “Unmark as Answer” if a marked post does not actually answer your question.
    This can be beneficial to other community members reading the thread.
  • Re: TreeView adapter problem

    07-10-2007, 5:05 PM
    • Contributor
      3,298 point Contributor
    • Russ Helfand
    • Member since 09-14-2005, 6:22 PM
    • Groovybits.com
    • Posts 741

    It sounds like you are using somewhat outdated versions of the adapters. The final version from Microsoft is what can be downloaded at http://www.asp.net/cssadapters. There is an even better version (with more fixes) at http://www.codeplex.com/cssfriendly. Hope this helps...

    Russ Helfand
    Groovybits.com
  • Re: TreeView adapter problem

    07-10-2007, 7:26 PM
    • Member
      100 point Member
    • ahsteele
    • Member since 01-19-2007, 9:34 PM
    • Albuquerque, NM
    • Posts 112

    I downloaded the CSSFriendly.dll and CSSFriendlyAdapters.browser files from http://www.codeplex.com/cssfriendly.  I removed all references to the previous adapters and added the appropriate reference to the CSSFriendly.dll.  I am experiencing the same behavior as before in that I get a call for each node checked in the TreeView.  I've placed my code below in case I missed something obvious.

     

      <asp:TreeView ID="HierarchyTreeView" runat="server"
           OnAdaptedTreeNodeCheckChanged="HierarchyTreeView_OnTreeNodeCheckChanged"
           OnPreRender="HierarchyTreeView_PreRender" />
      <asp:Button id="Submit" Text="Add Items to Cart" runat="server" UseSubmitBehavior="true" />

      

     

        public void HierarchyTreeView_OnTreeNodeCheckChanged(object sender, TreeNodeEventArgs e)
        {
            HierarchyTreeView.CheckedNodes.Count
        }
      
    Please remember to click “Mark as Answer” on the post that helps you, and to click “Unmark as Answer” if a marked post does not actually answer your question.
    This can be beneficial to other community members reading the thread.
  • Re: TreeView adapter problem

    07-11-2007, 7:26 PM
    • Member
      100 point Member
    • ahsteele
    • Member since 01-19-2007, 9:34 PM
    • Albuquerque, NM
    • Posts 112

    Just to be sure I started a new Web Project using the dll and browser files from http://www.codeplex.com/cssfriendly.  I had the same problem.  I then downloaded the source files and placed those into yet another new Web Project.  I created a very simple TreeView with a very simple method to be called OnTreeNodeCheckChanged (code below).  The same problem occurred and also occurred in the provided examples.

        <form id="form1" runat="server">
        <div>
            <asp:TreeView ID="TreeView1" runat="server" OnAdaptedTreeNodeCheckChanged="TreeView1_TreeNodeCheckChanged">
              <Nodes>
                <asp:TreeNode Text="test1" Value="test1" ShowCheckBox="true" />
                <asp:TreeNode Text="test2" Value="test2" ShowCheckBox="true" />
                <asp:TreeNode Text="test3" Value="test3" ShowCheckBox="true" />
              </Nodes>
            </asp:TreeView>
            <asp:Label runat="server" ID="myCount" /><br />
            <asp:Button ID="Button1" runat="server" Text="Button" />
        </div>
        </form>
     

        public void TreeView1_TreeNodeCheckChanged(object sender, TreeNodeEventArgs e)
        {
            myCount.Text = TreeView1.CheckedNodes.Count.ToString();
        }

    In walking through how my TreeView1_TreeNodeCheckChanged method was called upon when OnTreeNodeCheckChanged event was raised I was able to determine to a degree why the method is being called multiple times.  In the TreeViewAdapter class there is a method called UpdateCheckmarks.  This method calls Extender.RaiseAdapterEvent foreach TreeNode in the passed TreeNodeCollection that is checked.  I changed the method by adding a check ensuring that _checkboxIndex was equal to the TreeNodeCollection.count and only when it is calling the Extender.RaiseAdaptedEvent (meaning that Extender.RaiseAdaptedEvent is only called on the last iteration through the collection).  My change to the UpdateCheckmarks method is below (lines 15, 16, and 18 are new).

    1            private void UpdateCheckmarks(TreeNodeCollection items)
    2            {
    3                TreeView treeView = Control as TreeView;
    4                if ((treeView != null) && (items != null))
    5                {
    6                    foreach (TreeNode item in items)
    7                    {
    8                        if (IsCheckbox(treeView, item))
    9                        {
    10                           string name = treeView.UniqueID + "n" + _checkboxIndex.ToString() + "CheckBox";
    11                           bool bIsNowChecked = (Page.Request.Form[name] != null);
    12                           if (item.Checked != bIsNowChecked)
    13                           {
    14                               item.Checked = bIsNowChecked;
    15                               if (_checkboxIndex == items.Count)
    16                               {
    17                                   Extender.RaiseAdaptedEvent("TreeNodeCheckChanged", new TreeNodeEventArgs(item));
    18                               }
    19                           }
    20                           _checkboxIndex++;
    21                       }
    22   
    23                       if (HasChildren(item))
    24                       {
    25                           UpdateCheckmarks(item.ChildNodes);
    26                       }
    27                   }
    28               }
    29           }
    

    I realize this probably bastardizes something fundamental that is presently outside of my understanding, but it does fix the problem.  Assuming that I am right and I have violated a .Net core fundamental or something else fundamental to the adapters a little guidance would be greatly appreciated.

    Please remember to click “Mark as Answer” on the post that helps you, and to click “Unmark as Answer” if a marked post does not actually answer your question.
    This can be beneficial to other community members reading the thread.
  • Re: TreeView adapter problem

    07-11-2007, 7:49 PM
    • Member
      100 point Member
    • ahsteele
    • Member since 01-19-2007, 9:34 PM
    • Albuquerque, NM
    • Posts 112

    Scratch that, the above only works if the last item in the TreeNodeCollection is checked.  Back to the drawing board.

    Please remember to click “Mark as Answer” on the post that helps you, and to click “Unmark as Answer” if a marked post does not actually answer your question.
    This can be beneficial to other community members reading the thread.
Page 1 of 2 (21 items) 1 2 Next >