From: Scott on
When populating a Treeview in code, I am getting "duplicate" nodes.
They appear in the treeview, but don't seem to exist when I iterate
through the node collections.

This is what I get:

http://www.emick.us/Capture.JPG

and this is my code. I am baffled.

Scott Emick

Public Class MainForm
Private Sub ProcessButton_Click(ByVal sender As System.Object,
ByVal e As System.EventArgs) Handles ProcessButton.Click
Dim ds1 As New DS
Dim cn As New SqlConnection(My.Settings.WINDY)
cn.Open()
Dim cmd As New SqlCommand
cmd.Connection = cn
cmd.CommandText = "SELECT coalesce([MASTER NUMBER],-1) AS
MASTER_NUMBER FROM SALESTRANSACTIONS WHERE [SOP NUMBER] = '" &
OrderNumberTextBox.Text & "'"
Dim MasterNumber As Integer = cmd.ExecuteScalar
cmd.CommandText = "SELECT [SOP NUMBER], [ORIGINAL NUMBER] FROM
SALESTRANSACTIONS WHERE [MASTER NUMBER] = " & MasterNumber
Dim da As New SqlDataAdapter(cmd)
da.Fill(ds1.OrderTree)
For rc As Integer = 0 To (ds1.OrderTree.Count - 1)
Dim dr As DS.OrderTreeRow = ds1.OrderTree(rc)
If dr.ORIGINAL_NUMBER = "" Then
OrderTreeView.Nodes.Add(dr.SOP_NUMBER)
Console.WriteLine(dr.SOP_NUMBER)
OrderTreeView.ExpandAll()
Application.DoEvents()
Else
'try to find the node to add to
For tc As Integer = 0 To (OrderTreeView.Nodes.Count -
1)
Dim rn As TreeNode = FindNode(dr.ORIGINAL_NUMBER,
OrderTreeView.Nodes(tc))
If Not rn Is Nothing Then
rn.Nodes.Add(dr.SOP_NUMBER)
OrderTreeView.ExpandAll()
Application.DoEvents()
Exit For
End If

Next
End If
Next
End Sub
Private Function FindNode(ByRef Original_Number As String, ByRef
nd As TreeNode) As TreeNode
If nd.Text = Original_Number Then
Return nd
End If
If nd.Nodes.Count > 0 Then
For Each sn As TreeNode In nd.Nodes
Dim rn As TreeNode = FindNode(Original_Number, sn)
If Not rn Is Nothing Then
Return rn
End If
Next
End If
Return Nothing
End Function
From: Scott on
Funny I changed my arguments to the FindNode function from ByRef to
ByVal and the problems has stopped. Very odd.

Private Function FindNode(ByVal Original_Number As String, ByVal nd As
TreeNode) As TreeNode

On Apr 8, 11:52 am, Scott <scott.em...(a)gmail.com> wrote:
> When populating a Treeview in code, I am getting "duplicate" nodes.
> They appear in the treeview, but don't seem to exist when I iterate
> through the node collections.
>
> This is what I get:
>
> http://www.emick.us/Capture.JPG
>
> and this is my code.  I am baffled.
>
> Scott Emick
>
> Public Class MainForm
>     Private Sub ProcessButton_Click(ByVal sender As System.Object,
> ByVal e As System.EventArgs) Handles ProcessButton.Click
>         Dim ds1 As New DS
>         Dim cn As New SqlConnection(My.Settings.WINDY)
>         cn.Open()
>         Dim cmd As New SqlCommand
>         cmd.Connection = cn
>         cmd.CommandText = "SELECT coalesce([MASTER NUMBER],-1) AS
> MASTER_NUMBER FROM SALESTRANSACTIONS WHERE [SOP NUMBER] = '" &
> OrderNumberTextBox.Text & "'"
>         Dim MasterNumber As Integer = cmd.ExecuteScalar
>         cmd.CommandText = "SELECT [SOP NUMBER], [ORIGINAL NUMBER] FROM
> SALESTRANSACTIONS WHERE [MASTER NUMBER] = " & MasterNumber
>         Dim da As New SqlDataAdapter(cmd)
>         da.Fill(ds1.OrderTree)
>         For rc As Integer = 0 To (ds1.OrderTree.Count - 1)
>             Dim dr As DS.OrderTreeRow = ds1.OrderTree(rc)
>             If dr.ORIGINAL_NUMBER = "" Then
>                 OrderTreeView.Nodes.Add(dr.SOP_NUMBER)
>                 Console.WriteLine(dr.SOP_NUMBER)
>                 OrderTreeView.ExpandAll()
>                 Application.DoEvents()
>             Else
>                 'try to find the node to add to
>                 For tc As Integer = 0 To (OrderTreeView..Nodes.Count -
> 1)
>                     Dim rn As TreeNode = FindNode(dr.ORIGINAL_NUMBER,
> OrderTreeView.Nodes(tc))
>                     If Not rn Is Nothing Then
>                         rn.Nodes.Add(dr.SOP_NUMBER)
>                         OrderTreeView.ExpandAll()
>                         Application.DoEvents()
>                         Exit For
>                     End If
>
>                 Next
>             End If
>         Next
>     End Sub
>     Private Function FindNode(ByRef Original_Number As String, ByRef
> nd As TreeNode) As TreeNode
>         If nd.Text = Original_Number Then
>             Return nd
>         End If
>         If nd.Nodes.Count > 0 Then
>             For Each sn As TreeNode In nd.Nodes
>                 Dim rn As TreeNode = FindNode(Original_Number, sn)
>                 If Not rn Is Nothing Then
>                     Return rn
>                 End If
>             Next
>         End If
>         Return Nothing
>     End Function

From: Patrice on
> Funny I changed my arguments to the FindNode function from ByRef to
> ByVal and the problems has stopped. Very odd.

This is expected. The recursive FindNode calls behaves as if you are doing
nd=sn and then OrderTreeView.Nodes(tc)=nd...

Keep in mind that ByRef still passes the original value while ByVal
transmits a copy...

Though it doesn't make a difference when accessing object members (a pointer
(which is basically what an object is) or the copy of a pointer still points
to the same location), changing the object argument itself still does (i.e
you change the pointer itself).

As here you obviously didn't want to change anything, why to use ByRef as a
default ? I would suggest always using ByVal as a default...

--
Patrice









From: Scott on
On Apr 8, 2:12 pm, "Patrice" <http://www.chez.com/scribe/> wrote:
> > Funny I changed my arguments to the FindNode function from ByRef to
> > ByVal and the problems has stopped.  Very odd.
>
> This is expected. The recursive FindNode calls behaves as if you are doing
> nd=sn and then OrderTreeView.Nodes(tc)=nd...
>
> Keep in mind that ByRef still passes the original value while ByVal
> transmits a copy...
>
> Though it doesn't make a difference when accessing object members (a pointer
> (which is basically what an object is) or the copy of a pointer still points
> to the same location), changing the object argument itself still does (i.e
> you change the pointer itself).
>
> As here you obviously didn't want to change anything, why to use ByRef as a
> default ? I would suggest always using ByVal as a default...
>
> --
> Patrice

I normally do use byval as a default...

Normally the only reasons I use ByRef is either to change something
like you said, or also if the object is very large like a huge dataset
or something it seems like a waste to make a copy of it.

But once in a great while, I get "creative" when doing some ad-hoc
coding....
From: Scott on
On Apr 9, 8:18 am, Scott <scott.em...(a)gmail.com> wrote:
> On Apr 8, 2:12 pm, "Patrice" <http://www.chez.com/scribe/> wrote:
>
>
>
> > > Funny I changed my arguments to the FindNode function from ByRef to
> > > ByVal and the problems has stopped.  Very odd.
>
> > This is expected. The recursive FindNode calls behaves as if you are doing
> > nd=sn and then OrderTreeView.Nodes(tc)=nd...
>
> > Keep in mind that ByRef still passes the original value while ByVal
> > transmits a copy...
>
> > Though it doesn't make a difference when accessing object members (a pointer
> > (which is basically what an object is) or the copy of a pointer still points
> > to the same location), changing the object argument itself still does (i.e
> > you change the pointer itself).
>
> > As here you obviously didn't want to change anything, why to use ByRef as a
> > default ? I would suggest always using ByVal as a default...
>
> > --
> > Patrice
>
> I normally do use byval as a default...
>
> Normally the only reasons I use ByRef is either to change something
> like you said, or also if the object is very large like a huge dataset
> or something it seems like a waste to make a copy of it.
>
> But once in a great while, I get "creative" when doing some ad-hoc
> coding....

And in case anyone else ever has use for some code that displays order
hierarchy in Dynamics GP - Great Plains this is the code that ended up
working. I was just doing for myself, so yes it is sloppy! If I end
up using the logic in one of my projects I will probably create a
class in a library that returns an xml representation of the sop
document heirarchy and then use that for whatever purpose I need it
such as finding the status of individual items from a web order that
has been fulfilled through great plains.

Private Sub ProcessButton_Click(ByVal sender As System.Object,
ByVal e As System.EventArgs) Handles ProcessButton.Click
OrderTreeView.Nodes.Clear()
Dim ds1 As New DS
Dim cn As New SqlConnection(My.Settings.WINDY)
cn.Open()
Dim cmd As New SqlCommand
cmd.Connection = cn
cmd.CommandText = "SELECT coalesce([MASTER NUMBER],-1) AS
MASTER_NUMBER FROM SALESTRANSACTIONS WHERE [SOP NUMBER] = '" &
OrderNumberTextBox.Text & "'"
Dim MasterNumber As Integer = cmd.ExecuteScalar
cmd.CommandText = "SELECT [SOP NUMBER], [ORIGINAL NUMBER],
[sop type] FROM SALESTRANSACTIONS " & _
" WHERE [MASTER NUMBER] = " & MasterNumber & " order by
[original number]"
Dim da As New SqlDataAdapter(cmd)
da.Fill(ds1.OrderTree)
Dim otr As DS.OrderTreeRow() = ds1.OrderTree.Select("[ORIGINAL
NUMBER]=''")
If otr.Length > 0 Then
Dim SOP_NUMBER As String = otr(0).SOP_NUMBER
Dim SOP_TYPE As String = otr(0).sop_type
Dim curnode As TreeNode =
OrderTreeView.Nodes.Add(SOP_NUMBER & " (" & SOP_TYPE & ")")
curnode.Expand()
ListNodeItems(SOP_NUMBER, SOP_TYPE, curnode)
FindChildren(curnode, ds1.OrderTree, SOP_NUMBER)
End If
End Sub
Private Sub FindChildren(ByVal curnode As TreeNode, ByVal ot As
DS.OrderTreeDataTable, ByVal SOP_NUMBER As String)
Dim otr As DS.OrderTreeRow() = ot.Select("[ORIGINAL NUMBER]='"
& SOP_NUMBER & "'")
If otr.Length > 0 Then
For cc As Integer = 0 To (otr.Length - 1)
Dim newnode As TreeNode =
curnode.Nodes.Add(otr(cc).SOP_NUMBER & " (" & otr(cc).SOP_TYPE & ")")
newnode.Expand()
ListNodeItems(otr(cc).SOP_NUMBER, otr(cc).SOP_TYPE,
newnode)
FindChildren(newnode, ot, otr(cc).SOP_NUMBER)
Next
End If
End Sub
Private Sub ListNodeItems(ByVal SOP_NUMBER As String, ByVal
SOP_TYPE As String, ByVal curnode As TreeNode)
Dim gvaOrderTypes As New DS.gvaOrderTypesDataTable
Dim gvaOrderTypesTA As New DSTableAdapters.gvaOrderTypesTA
gvaOrderTypesTA.Fill(gvaOrderTypes)
Dim sli As New DS.SOPLINEITEMSDataTable
Dim sli_table_adapter As New DSTableAdapters.SOPLINEITEMSTA
Dim otr As DS.gvaOrderTypesRow() =
gvaOrderTypes.Select("OrderTypeDesc = '" & SOP_TYPE & "'")
Dim sop_type_key As Integer = otr(0).OrderType
sli_table_adapter.Fill(sli, SOP_NUMBER, sop_type_key)
For Each li As DS.SOPLINEITEMSRow In sli.Rows
Dim itemnmbr As TreeNode = curnode.Nodes.Add(li.ITEMNMBR)
itemnmbr.Nodes.Add("QUANTITY " & li.QUANTITY)
itemnmbr.Nodes.Add("QTYCANCE " & li.QTYCANCE)
itemnmbr.Nodes.Add("QTYFULFI " & li.QTYFULFI)
itemnmbr.Nodes.Add("QTYTBAOR " & li.QTYTBAOR)
itemnmbr.Nodes.Add("QTYTOINV " & li.QTYTOINV)
Next
End Sub
Private Function FindNode(ByVal Original_Number As String, ByVal
nd As TreeNode) As TreeNode
If nd.Text = Original_Number Then
Return nd
End If
If nd.Nodes.Count > 0 Then
For Each sn As TreeNode In nd.Nodes
Dim rn As TreeNode = FindNode(Original_Number, sn)
If Not rn Is Nothing Then
Return rn
End If
Next
End If
Return Nothing
End Function

-- Yes this table should be called SOPTypes, not ordertypes.......This
is the table for the SOPTYPE lookup

CREATE TABLE [dbo].[gvaOrderTypes](
[OrderType] [int] NOT NULL,
[OrderTypeDesc] [varchar](255) NOT NULL,
CONSTRAINT [PK_gvaOrderTypes] PRIMARY KEY CLUSTERED
(
[OrderType] ASC
)WITH (PAD_INDEX = OFF, STATISTICS_NORECOMPUTE = OFF, IGNORE_DUP_KEY
= OFF, ALLOW_ROW_LOCKS = ON, ALLOW_PAGE_LOCKS = ON) ON [PRIMARY]
) ON [PRIMARY]
GO
INSERT [dbo].[gvaOrderTypes] ([OrderType], [OrderTypeDesc]) VALUES (1,
N'Quote')
INSERT [dbo].[gvaOrderTypes] ([OrderType], [OrderTypeDesc]) VALUES (2,
N'Order')
INSERT [dbo].[gvaOrderTypes] ([OrderType], [OrderTypeDesc]) VALUES (3,
N'Invoice')
INSERT [dbo].[gvaOrderTypes] ([OrderType], [OrderTypeDesc]) VALUES (4,
N'Return')
INSERT [dbo].[gvaOrderTypes] ([OrderType], [OrderTypeDesc]) VALUES (5,
N'Back Order')