CodeGuru Home VC++ / MFC / C++ .NET / C# Visual Basic VB Forums Developer.com
Results 1 to 8 of 8
  1. #1
    Join Date
    Jun 2005
    Location
    JHB South Africa
    Posts
    3,772

    [RESOLVED] FOR EACH ... bug/problem/quirk ....

    Well i just found this one, (will be added to my article as soon as a decent patch/alternative can be found)...

    look at the following code snip ...
    Code:
                For Each Childnode As TreeNode In TreeView1.Nodes
                    If Childnode.Nodes.Count = 0 Then
                        Childnode.Remove()
                    End If
                Next
    This looks just so simple ... If the node is empty delete it ...

    NOPE ....

    Simply put, it skips nodes... How And Why i do know ... but i need to find a way to do it... ( in a single pass)

    A little background.

    I have a treeview that has 9 base nodes (Groups), that get populated with specific data according to what token has been read..
    Some tokens populate all 9 groups, some only 4, and others only 2. The groups are filled in a semi random way... all empty groups need to be removed from the tree, as they hold no useful info ..


    HOW & WHY it skips nodes...

    For those that are interested to know the how and why's ..
    Think of the following 'FOR NEXT' Loop (On The Fly Code)
    Code:
    Total = Array.ItemCount
    For X = 1 to Total
        If Array(X) = 0 then
            'Code to remove item from array
            For Y = X to Total -1
                Array(Y) = Array(Y+1)
            Next Y
            Total = Total -1
       End If
    Next X
    Lets now validate this small loop ..
    Array = {0, 0, 3, 4, 5, 6, 7, 8, 9, 0)

    On the first pass we will get: -- X =1
    Before: Array = {0, 0, 3, 4, 5, 6, 7, 8, 9, 0)
    After :Array = {0, 3, 4, 5, 6, 7, 8, 9, 0 , 0)

    But then on the second pass : -- X= 2
    Before: Array = {0, 3, 4, 5, 6, 7, 8, 9, 0, 0)
    After :Array = {0, 3, 4, 5, 6, 7, 8, 9, 0 , 0)

    As you can see the second item is now acctualy the first one.. and with X = 2 we skip it ...

    this is one reason why when deleting items from arrays you do it from the backwards.Last item first...
    so the loop should be something along this line
    Code:
    Total = Array.ItemCount
    For X = Total to 1 Step -1
        If Array(X) = 0 then
            'Code to remove item from array
            For Y = X to Total -1
                Array(Y) = Array(Y+1)
            Next Y
            Total = Total -1
       End If
    Next X
    The problem here is that a 'FOR EACH' translates directly to a FOR Index = Min TO Max and suffers the delete skip problem ...

    Any one have ideas appart from
    Code:
                For Index As Integer = TreeView1.Nodes.Count - 1 To 0 Step -1
                    Dim Childnode As TreeNode = TreeView1.Nodes(Index)
                    If Childnode.Nodes.Count = 0 Then
                        Childnode.Remove()
                    End If
                Next
    As this is what i've done already to solve the problem ..
    However I'm looking for a NON INDEXED method .. IE.. For Each ...... Step -1..
    Articles VB6 : Break the 2G limit - Animation 1, 2 VB.NET : 2005/8 : Moving Images , Animation 1 , 2 , 3 , User Controls
    WPF Articles : 3D Animation 1 , 2 , 3
    Code snips: VB6 Hex Edit, IP Chat, Copy Prot., Crop, Zoom : .NET IP Chat (V4), Adv. ContextMenus, click Hotspot, Scroll Controls
    Find me in ASP.NET., VB6., VB.NET , Writing Articles, My Genealogy, Forum
    All VS.NET: posts refer to VS.NET 2008 (Pro) unless otherwise stated.

  2. #2
    Join Date
    Aug 2005
    Location
    Imperial College London, England
    Posts
    490

    Re: FOR EACH ... bug/problem/quirk ....

    1) I thought that, in most cases, if you remove an item during a For Each, you got all sorts of strange results generally? I've had a number of programs crash when doing this kind of thing

    2) A quick work around is to do this, but it doesn't really answer you question:
    Code:
    For Each Childnode As TreeNode In TreeView1.Nodes
      Do While Childnode.Nodes.Count = 0
        Childnode = Childnode.NextNode
        Childnode.PrevNode.Remove()
      Loop
    Next
    Help from me is always guaranteed!*
    VB.NET code is made up on the spot with VS2008 Professional with .NET 3.5. Everything else is just made up on the spot.
    Please Remember to rate posts, use code tags, send me money and all the other things listed in the "Before you post" posts.

    *Guarantee may not be honoured.

  3. #3
    Join Date
    Jun 2005
    Location
    JHB South Africa
    Posts
    3,772

    Re: FOR EACH ... bug/problem/quirk ....

    Very nice try JavaJawa ... However... If the last item in the list is to be removed we land up with
    System.NullReferenceException was unhandled
    Message="Object reference not set to an instance of an object."
    and then the same will happen with the first item if we use
    Code:
        Childnode = Childnode.PrevNode
        Childnode.NextNode.Remove()
    The use of For Each is generally used for collections that are not indexed, or not sequentially indexed ...
    something to note, in .NET now, just about any collection has a sequential index, that can be used via Collection.Item(Index), but often it is so much easier to use a For Each loop ....

    Gremmy...
    Articles VB6 : Break the 2G limit - Animation 1, 2 VB.NET : 2005/8 : Moving Images , Animation 1 , 2 , 3 , User Controls
    WPF Articles : 3D Animation 1 , 2 , 3
    Code snips: VB6 Hex Edit, IP Chat, Copy Prot., Crop, Zoom : .NET IP Chat (V4), Adv. ContextMenus, click Hotspot, Scroll Controls
    Find me in ASP.NET., VB6., VB.NET , Writing Articles, My Genealogy, Forum
    All VS.NET: posts refer to VS.NET 2008 (Pro) unless otherwise stated.

  4. #4
    Join Date
    Mar 2002
    Location
    St. Petersburg, Florida, USA
    Posts
    12,125

    Re: FOR EACH ... bug/problem/quirk ....

    Gremmy,

    Modifying a collection invalidates the iterator. This is inherent in the design. The most common pattern is the gather/process pattern.

    Code:
    foreach (in real collection)
      if (qualifier)
         AttToRemovalList(...)
    foreach (in removasllist)
         RealCollection.Remove(...)
    What prevents you from using this pattern????

    The only alternative I can think of that is not "fragile" would be to implement a custom IEnumerable/IEnumerator for your collection....
    TheCPUWizard is a registered trademark, all rights reserved. (If this post was helpful, please RATE it!)
    2008, 2009,2010
    In theory, there is no difference between theory and practice; in practice there is.

    * Join the fight, refuse to respond to posts that contain code outside of [code] ... [/code] tags. See here for instructions
    * How NOT to post a question here
    * Of course you read this carefully before you posted
    * Need homework help? Read this first

  5. #5
    Join Date
    Jun 2005
    Location
    JHB South Africa
    Posts
    3,772

    Re: FOR EACH ... bug/problem/quirk ....

    Quote Originally Posted by TheCPUWizard View Post
    Gremmy,

    Modifying a collection invalidates the iterator. This is inherent in the design. The most common pattern is the gather/process pattern.

    Code:
    foreach (in real collection)
      if (qualifier)
         AttToRemovalList(...)
    foreach (in removasllist)
         RealCollection.Remove(...)
    What prevents you from using this pattern????

    The only alternative I can think of that is not "fragile" would be to implement a custom IEnumerable/IEnumerator for your collection....
    I hope you don't mind, but i'm going to use your phrase in my article, because it explains the conundrum very nicely... (Quoted of course)

    Thanks..
    Articles VB6 : Break the 2G limit - Animation 1, 2 VB.NET : 2005/8 : Moving Images , Animation 1 , 2 , 3 , User Controls
    WPF Articles : 3D Animation 1 , 2 , 3
    Code snips: VB6 Hex Edit, IP Chat, Copy Prot., Crop, Zoom : .NET IP Chat (V4), Adv. ContextMenus, click Hotspot, Scroll Controls
    Find me in ASP.NET., VB6., VB.NET , Writing Articles, My Genealogy, Forum
    All VS.NET: posts refer to VS.NET 2008 (Pro) unless otherwise stated.

  6. #6
    Join Date
    Mar 2007
    Location
    Argentina
    Posts
    579

    Re: FOR EACH ... bug/problem/quirk ....

    Quote Originally Posted by GremlinSA View Post
    ...
    Code:
    For Each Childnode As TreeNode In TreeView1.Nodes
        If Childnode.Nodes.Count = 0 Then
            Childnode.Remove()
        End If
    Next
    ...
    Never used that control, so this may not work, but I would try:
    Code:
    For Each Childnode As TreeNode In TreeView1.Nodes.toarray 'or clone
        If Childnode.Nodes.Count = 0 Then
            TreeView1.nodes.item(Childnode.index).Remove()
        End If
    Next
    [Vb.NET 2008 (ex Express)]

  7. #7
    Join Date
    Mar 2007
    Location
    Argentina
    Posts
    579

    Re: FOR EACH ... bug/problem/quirk ....

    Quote Originally Posted by Marraco View Post
    Never used that control, so this may not work, but I would try:
    Code:
    For Each Childnode As TreeNode In TreeView1.Nodes.toarray 'or clone
        If Childnode.Nodes.Count = 0 Then
            TreeView1.nodes.item(Childnode.index).Remove()
        End If
    Next
    Not Childnode.index!. Maybe other identificator?
    [Vb.NET 2008 (ex Express)]

  8. #8
    Join Date
    Jun 2005
    Location
    JHB South Africa
    Posts
    3,772

    Re: FOR EACH ... bug/problem/quirk ....

    Marroco...

    No matter which way to try it, You still deleting/removing an item from the list, and this action is what is causing the problems..

    Using the gather/ process method that CPU sugested, is the best method..

    I've implemented it and it works 100s
    Articles VB6 : Break the 2G limit - Animation 1, 2 VB.NET : 2005/8 : Moving Images , Animation 1 , 2 , 3 , User Controls
    WPF Articles : 3D Animation 1 , 2 , 3
    Code snips: VB6 Hex Edit, IP Chat, Copy Prot., Crop, Zoom : .NET IP Chat (V4), Adv. ContextMenus, click Hotspot, Scroll Controls
    Find me in ASP.NET., VB6., VB.NET , Writing Articles, My Genealogy, Forum
    All VS.NET: posts refer to VS.NET 2008 (Pro) unless otherwise stated.

Tags for this Thread

Posting Permissions

  • You may not post new threads
  • You may not post replies
  • You may not post attachments
  • You may not edit your posts
  •  





Click Here to Expand Forum to Full Width

Featured