Treeview.FindNode Not working for me on 2 levels deep - sql

I have a treeview which has a database structure as such:
Id Unit ParentOrganizationalUnitId Level
1 City wide NULL 0
219 Finance Division 218 1
4 City Hall Client Services 3 2
This is is not all the data this is just three levels showing for reference purposes.
For Each row In SearchTag
Dim parentNode As New TreeNode
If row.Level = 0 Then
parentNode.Text = row.SearchTag.ToString
parentNode.Value = row.Id.ToString
trvSearchTag.Nodes.Add(parentNode)
ElseIf row.Level = 1 Then
Dim childNode As New TreeNode
Dim parentchildNode As New TreeNode
childNode.Text = row.SearchTag.ToString
childNode.Value = row.Id.ToString
parentchildNode = trvSearchTag.FindNode(row.ParentSearchTagID)
If Not parentchildNode Is Nothing Then
parentchildNode.ChildNodes.Add(childNode)
End If
ElseIf row.Level = 2 Then
Dim childNode1 As New TreeNode
Dim parentchildNode1 As New TreeNode
childNode1.Text = row.SearchTag.ToString
childNode1.Value = row.Id.ToString
parentchildNode1 = trvSearchTag.FindNode(row.ParentSearchTagID)
If Not parentchildNode1 Is Nothing Then
parentchildNode1.ChildNodes.Add(childNode1)
End If
End If
Next
I have this code ^^^^ which populates the treeview accordingly. the issue is my findnode function only worked on level 0 and level 1 when it goes to find level 2 options it returns nothing? Why is it doing that?
Side notes.
Structure cannot change due to business req
Code can change.
I checked to make sure when it goes looking for a node with a parent id of say 3 that 3 actually did exist in the treeview prior to the search as its added on level 1 accordingly. via debugging the code and also via running the SPROC to see the results exist.

Assuming that you're using the WebForms TreeView control:
The FindNode method takes a path to a node, not just the value of the node, as a parameter.
So, assuming your tree looks something like this:
City wide
Finance Division
City Hall Client Services
... and that each node has the appropriate ID as its Value property, code to find City Hall Client Services would look something like this:
orgTreeView.FindNode("1/219/4")
Just this:
orgTreeView.FindNode("4")
... won't work, because 4 is not a top-level node.

Related

Sort issue with integers [closed]

Closed. This question needs debugging details. It is not currently accepting answers.
Edit the question to include desired behavior, a specific problem or error, and the shortest code necessary to reproduce the problem. This will help others answer the question.
Closed 2 years ago.
Improve this question
I am trying to make a leader board that puts highest scores at the top or left with this layout
99 - james,
90 - will,
80 - dan,
70 - phil,
60 - kevin,
570 - jim,
50 - ben,
40 - david,
30 - jose,
220 - peter,
20 - tony,
10 - nick,
The .sort command doesn't work for numbers 3 digits and up i have a list that i am tying to sort but it is not working.
This is what i am currently working with.
leaderboard.Sort()
leaderboard.Reverse()
It does sort numbers under 100 perfectly well this is the only issue i have.
Dim leaderboard As New List(Of String)
Using Reader As New StreamReader("C:\Users\1111\OneDrive\Documents\Leaderboard.txt")
While Reader.EndOfStream = False
leaderboard.Add(Reader.ReadLine())
End While
End Using
leaderboard.Sort()
leaderboard.Reverse()
First I made a Structure as a template to hold your data. It has 2 properties. One to hold the Score and one to hold the name.
Private Structure Leader
Public Property Score As Integer
Public Property Name As String
End Structure
The code starts out by creating a new list of Leader (the name of the structure).
I used the File class from System.IO (you will need to add this to the list of Imports at the top of the code file). .ReadAllLines returns an array of strings, each element is a single line from the text file.
Then we loop through each line, splitting the line by the hyphen. This will give your an array of strings with 2 elements. Before you try to convert the the first element to an Integer be sure to trim off any spaces. The second element of the array will contain the name and need to be trimmed. I also replaced the comma with an empty string.
Finally, a bit of Linq magic orders the list in descending order by score into another list. Function(lead) is a function that takes each item in the original list and tests its Score property. I called .ToList at the end so orderedLeader could be display in a DataGridView.
Private Sub OPCode()
Dim leaderboard As New List(Of Leader)
Dim lines = File.ReadAllLines("leaderboard.txt")
For Each line In lines
Dim splitLine = line.Split("-"c)
Dim sc = CInt(splitLine(0).Trim)
Dim nm = splitLine(1).Trim.Replace(",", "")
leaderboard.Add(New Leader With {.Score = sc, .Name = nm})
Next
Dim orderedLeaderbord = leaderboard.OrderByDescending(Function(lead) lead.Score).ToList
DataGridView1.DataSource = orderedLeaderbord
End Sub

VBA dynamically populate nested data structure

I have a few SQL tables, some which are linked, that I would like to query once and store locally in a single variable. I can't predict the length of the data ahead of time so I need a dynamic data structure.
Example data I'm querying:
Table 1
NameA
Red
Green
Blue
Table 2
NameA NameB
Red A
Red B
Red C
Blue D
Blue E
Green F
Table 3
NameA NameC
Red One
Blue Two
Blue Three
Blue Four
Blue Five
Green Six
Green Seven
I need to be able to filter and access NameB and NameC based on NameA values. I would prefer a nested dictionary structure where I could query like below:
Table1("0") 'will equal "Red"
Table2("Red")("0") 'will equal "A"
Table2("Blue")("1") 'will equal "E"
Table3("Green")("1") 'will equal "Seven"
'note: point here is data structure, not order of results
I have tried using VBA's nested dictionaries but have been unable to get around the lack of a "deep copy" function. One algorithm I wrote:
With SqlQueryResult
i = 0
Do Until .EOF
Call Table1.Add(CStr(i), .Fields(0).Value)
i = i + 1
.MoveNext
Loop
End With
For Each key In Table1.Keys
SqlQueryResult = GetResultsFromQuery(SELECT NameB WHERE NameA = Table1(key))
With SqlQueryResult
i = 0
Do Until .EOF
Call TempDict.Add(CStr(i), .Fields(0).Value)
i = i + 1
.MoveNext
Loop
End With
Set Table2(Table1(key)) = TempDict
TempDict.RemoveAll
Next key
Unfortunately assigning a Dict to another Dict only sets a reference and doesn't actually copy over data -- when I delete TempDict, the nested data from Table2 is also removed.
I also can't have a new dictionary per "branch" in the nest structure as I need this data to be available at a module-level scope, and therefore need to define these in the top of the module before program execution.
I've looked at multi-dimentional dynamic arrays - these can't be assigned to a parent structure like a dictionary. I also can't predict the size of each of these tables, e.g. Table1 might be 5/20/100/etc in size, Red may have 2/5/100/etcetc results in Table 2, Blue have 1/20/etcetc results in Table 2. Redim only works on a single dimension in an array.
I've had a brief look at Collections as well, and I am not sure these are viable.
I don't have much experience with classes and I would rather avoid a very involved process - I want it to be easy to add linked and unliked (i.e. data linked to Table 1, like Table 2 and 3, vs stand-alone data not related to any other table) to this program should I need to in the future. (My benchmark for "easy" is a pandas dataframe in python).
A simple wrapper class for scripting dictionaries which implements a clone method. This should work fine with primitive datatypes.
Option Explicit
Private Type State
Dict As scripting.Dictionary
End Type
Private s As State
Private Sub Class_Initialize()
Set s.Dict = New scripting.Dictionary
End Sub
Public Function Clone()
Dim myClone As scripting.Dictionary
Set myClone = New scripting.Dictionary
Dim myKey As Variant
For Each myKey In s.Dict
myClone.Add myKey, s.Dict.Item(myKey)
Next
Set Clone = myClone
End Function
Public Property Get Item(ByVal Key As Variant) As Variant
Item = s.Dict.Item(Key)
End Property
Public Property Set Item(ByVal Key As Variant, ByVal Value As Variant)
s.Dict.Item(Key) = Value
End Property
Public Sub Add(ByVal Key As Variant, ByVal Item As Variant)
s.Dict.Add Key, Item
End Sub
You will now be able to say
Set Table2.Item(Table1.Item(key)) = TempDict.Clone

Using a 3-column Collection in Excel VBA and searching it

I am building an algorithm in excel vba to search for paths in a network. I am new to programming these types of problems. Please don't suggest alternate software. The problem should be very simple.
Problem Description:
Search a collection of data representing flows on arcs (3 "columns": from, to, flow)
Identify path (start at source, find flow to "to", look up that "to" in the "from" field, find flow to that "to", and so on until another "from" cannot be found) from source to end of each path.
Data looks like this:
fromnode tonode flow
1 2 4
2 3 3
3 4 2
4 5 1
7 6 1
8 7 2
Biggest hurdle:
I am using a Collection to hold this data and setting it with the code below.
Dim y As Collection
Set y = New Collection
y.Add Sheets("FlowDecomp_Solve").Range("fromtoflow").Value
The data gets pulled in, but it looks like this:
(tried a pic, but I'm a new user)
Item 1
Item 1(1)
Item 1 (1,1) 1
Item 1 (1,2) 2
Item 1 (1,3) 4
So it shows that the Collection has 1 item instead of my # of arcs. How do I access the Item1(1,2) type address for the collection. Does each special value have a unique key? How do I search through my collection and remove a specific row after I've used it in the code?
THANK YOU SO MUCH FOR ANY HELP.
After much trial and error, I've decided to make my original data an array and search it like this (d is down the array, a is across):
For d = LBound(arcflow(), 1) To UBound(arcflow(), 1)
For a = LBound(arcflow(), 2) To UBound(arcflow(), 2)
If a = 1 Then
fromnode = arcflow(d, a)
ElseIf a = 2 Then
tonode = arcflow(d, a)
ElseIf a = 3 Then
flow = arcflow(d, a)
'write into node-node matrix
Sheets("FlowDecomp_Solve").Range("nodenodemtrx").Cells(fromnode, tonode).value = 1
End If
Next a
Next d
Then to trace the path, I add the from and to nodes to a collection called Path until it can't find another arc and I write the path out, empty the collection, update the values, and start again.
Hope this helps someone else...

SSIS - Script Component, Split single row to multiple rows (Parent Child Variation)

Thanks in advance for your help. I'm in need of help on writing SSIS script component to delimit single row to multiple rows. There were many helpful blog and post I looked at below:
http://beyondrelational.com/ask/public/questions/1324/ssis-script-component-split-single-row-to-multiple-rows-parent-child-variation.aspx
http://bi-polar23.blogspot.com/2008/06/splitting-delimited-column-in-ssis.html
However, I need a little extra help on coding to complete the project. Basically here's what I want to do.
Input data
ID Item Name
1 Apple01,02,Banana01,02,03
2 Spoon1,2,Fork1,2,3,4
Output data
ParentID ChildID Item Name
1 1 Apple01
1 2 Apple02
1 3 Banana01
1 4 Banana02
1 5 Banana03
2 1 Spoon1
2 2 Spoon2
2 3 Fork1
2 4 Fork2
2 5 Fork3
2 6 Fork4
Below is my attempt to code, but feel free to revise whole if it's illogic. SSIS Asynchronous output is set.
Public Overrides Sub Input0_ProcessInputRow(ByVal Row As Input0Buffer)
Dim posID As Integer, childID As Integer
Dim delimiter As String = ","
Dim txtHolder As String, suffixHolder As String
Dim itemName As String = Row.ItemName
Dim keyField As Integer = Row.ID
If Not (String.IsNullOrEmpty(itemList)) Then
Dim inputListArray() As String = _
itemList.Split(New String() {delimiter}, _
StringSplitOptions.RemoveEmptyEntries)
For Each item As String In inputListArray
Output0Buffer.AddRow()
Output0Buffer.ParentID = keyField
If item.Length >= 3 Then
txtHolder = Trim(item)
Output0Buffer.ItemName = txtHolder
'when item length is less than 3, it's suffix
Else
suffixHolder = Trim(item)
txtHolder = Left(txtHolder.ToString(), Len(txtHolder) _
- Len(suffixHolder)) & suffixHolder.ToString()
Output0Buffer.ItemName = txtHolder
End If
Next
End If
End Sub
The current code produces the following output
ID Item Name
1 Apple01
1 02
1 Banana01
1 02
1 03
2 Spoon1
2 2
2 Fork1
2 2
2 3
2 4
If I come across as pedantic in this response, it is not my intention. Based on the comment "I'm new at coding and having a problem troubleshooting" I wanted to walk through my observations and how I came to them.
Problem analysis
The desire is to split a single row into multiple output rows based on a delimited field associated to the row.
The code as it stands now is generating the appropriate number of rows so you do have the asynchronous part (split) of the script working so that's a plus. What needs to happen is we need to 1) Populate the Child ID column 2) Apply the item prefix to all subsequent row when generating the child items.
I treat most every problem like that. What am I trying to accomplish? What is working? What isn't working? What needs to be done to make it work. Decomposing problems into smaller and smaller problems will eventually result in something you can do.
Code observations
Pasting in the supplied code resulted in an error that itemList was not declared. Based on usage, it seems that it was intended to be itemName.
After fixing that, you should notice the IDE indicating you have 2 unused variables (posID, childID) and that the variable txHolder is used before it's been assigned a value. A null reference exception could result at runtime. My coworker often remarks warnings are errors that haven't grown up yet so my advice to you as a fledgling developer is to pay attention to warnings unless you explicitly expect the compiler to warn you about said scenario.
Getting started
With a choice between solving the Child ID situation versus the name prefix/suffix stuff, I'd start with an easy one, the child id
Generating a surrogate key
That's the fancy title phrase that if you searched on you'd have plenty of hits to ssistalk or sqlis or any of a number of fabulously smart bloggers. Devil of course is knowing what to search on. No where do you ever compute or assign the child id value to the stream which of course is why it isn't showing up there.
We simply need to generate a monotonically increasing number which resets each time the source id changes. I am making an assumption that the inbound ID is unique in the incoming data like a sales invoice number would be unique and we are splitting out the items purchased. However if those IDs were repeated in the dataset, perhaps instead of representing invoice numbers they are salesperson id. Sales Person 1 could have another row in the batch selling vegetables. That's a more complex scenario and we can revisit if that better describes your source data.
There are two parts to generating our surrogate key (again, break problems down into smaller pieces). The first thing to do is make a thing that counts up from 1 to N. You have defined a childId variable to serve this. Initialize this variable (1) and then increment it inside your foreach loop.
Now that we counting, we need to push that value onto the output stream. Putting those two steps together would look like
childID = 1
For Each item As String In inputListArray
Output0Buffer.AddRow()
Output0Buffer.ParentId = keyField
Output0Buffer.ChildId = childID
' There might be VB shorthand for ++
childID = childID + 1
Run the package and success! Scratch the generate surrogate key off the list.
String mashing
I don't know of a fancy term for what needs to be done in the other half of the problem but I needed some title for this section. Given the source data, this one might be harder to get right. You've supplied value of Apple01, Banana01, Spoon1, Fork1. It looks like there's a pattern there (name concatenated with a code) but what it is it? Your code indicates that if it's less than 3, it's a suffix but how do you know what the base is? The first row uses a leading 0 and is two digits long while the second row does not use a leading zero. This is where you need to understand your data. What is the rule for identifying the "code" part of the first row? Some possible algorithms
Force your upstream data providers to provide consistent length codes (I think this has worked once in my 13 years but it never hurts to push back against the source)
Assuming code is always digits, evaluate each character in reverse order testing whether it can be cast to an integer (Handles variable length codes)
Assume the second element in the split array will provide the length of the code. This is the approach you are taking with your code and it actually works.
I made no changes to make the generated item name work beyond fixing the local variables ItemName/itemList. Final code eliminates the warnings by removing PosID and initializing txtHolder to an empty string.
Public Overrides Sub Input0_ProcessInputRow(ByVal Row As Input0Buffer)
Dim childID As Integer
Dim delimiter As String = ","
Dim txtHolder As String = String.Empty, suffixHolder As String
Dim itemName As String = Row.ItemName
Dim keyField As Integer = Row.ID
If Not (String.IsNullOrEmpty(itemName)) Then
Dim inputListArray() As String = _
itemName.Split(New String() {delimiter}, _
StringSplitOptions.RemoveEmptyEntries)
' The inputListArray (our split out field)
' needs to generate values from 1 to N
childID = 1
For Each item As String In inputListArray
Output0Buffer.AddRow()
Output0Buffer.ParentId = keyField
Output0Buffer.ChildId = childID
' There might be VB shorthand for ++
childID = childID + 1
If item.Length >= 3 Then
txtHolder = Trim(item)
Output0Buffer.ItemName = txtHolder
Else
'when item length is less than 3, it's suffix
suffixHolder = Trim(item)
txtHolder = Left(txtHolder.ToString(), Len(txtHolder) _
- Len(suffixHolder)) & suffixHolder.ToString()
Output0Buffer.ItemName = txtHolder
End If
Next
End If
End Sub

Comparing trees in a treeview

I want to be able to iterate through a tree and compare nodes one tree to the nodes in another tree of the same format.
EX: There are five categories.
1 - 5. Are all static and identical between both trees.
In 1. All static values. So i need to just compare the values of the nodes there.
In 2. This is comes from a KVP object and so these can be different in terms of number of nodes and their single children.
In 3. Same as 2 but there are 5 children
In 4-5 are the same as 1.
I was thinking of looping in the trees and having a different for loop for each category and checking the nodes contain the same values.
The dynamic one for 2 and 3 I would do something of the same, but check the size first then loop through if the size is the same.
If i find a difference I would change that nodes back color.
Is this the best method for me?
I don't think you have much of a choice but to do different comparison algorithms based on the data that in the tree since it seems that your nodes are symantically different depending on where they are in the tree.
Since I knew the depth...i did this:
For h As Integer = 0 To tree1.Nodes(0).Nodes.Count - 1
For i As Integer = 0 To tree1.Nodes(0).Nodes(h).Nodes.Count - 1
For j As Integer = 0 To tree1.Nodes(0).Nodes(h).Nodes(i).Nodes.Count - 1
If tree1.Nodes(0).Nodes(h).Nodes(i).Text <> _
tree2.Nodes(0).Nodes(h).Nodes(i).Text Then
tree2.Nodes(0).Nodes(h).Nodes(i).BackColor = Color.Red
tree2.Nodes(0).Nodes(h).Nodes(i).Nodes(j).Expand()
tree2.Nodes(0).Nodes(h).Nodes(i).Expand()
tree2.Nodes(0).Nodes(h).Expand()
tree2.Nodes(0).Expand()
tree1.Nodes(0).Nodes(h).Nodes(i).BackColor = Color.Red
tree1.Nodes(0).Nodes(h).Nodes(i).Nodes(j).Expand()
tree1.Nodes(0).Nodes(h).Nodes(i).Expand()
tree1.Nodes(0).Nodes(h).Expand()
tree1.Nodes(0).Expand()
ElseIf tree1.Nodes(0).Nodes(h).Nodes(i).Nodes(j).Text <> _
tree2.Nodes(0).Nodes(h).Nodes(i).Nodes(j).Text Then
tree2.Nodes(0).Nodes(h).Nodes(i).Nodes(j).BackColor = Color.Red
tree2.Nodes(0).Nodes(h).Nodes(i).BackColor = Color.Red
tree2.Nodes(0).Nodes(h).Nodes(i).Nodes(j).Expand()
tree2.Nodes(0).Nodes(h).Nodes(i).Expand()
tree2.Nodes(0).Nodes(h).Expand()
tree2.Nodes(0).Expand()
tree1.Nodes(0).Nodes(h).Nodes(i).Nodes(j).BackColor = Color.Red
tree1.Nodes(0).Nodes(h).Nodes(i).BackColor = Color.Red
tree1.Nodes(0).Nodes(h).Nodes(i).Nodes(j).Expand()
tree1.Nodes(0).Nodes(h).Nodes(i).Expand()
tree1.Nodes(0).Nodes(h).Expand()
tree1.Nodes(0).Expand()
End If
Next
Next
Next