We help IT Professionals succeed at work.

Building Collections of Objects based on their Tag Property

226 Views
Last Modified: 2017-05-20
Hi Experts.

I'm building a Windows Form that includes a large assortment of labels, buttons, scroll bars, etc. across multiple pages on a complex Multi-Tab control. The program is essentially designed to keep score during a 9 ball game which can be very involved in APA leagues.

The program is updating these values throughout the life of the program and I thought it would be a good idea to create collections with like controls. For example, if the one ball is pocketed, that means I need to update about six controls including four labels, a vertical scroll bar and a progress bar. Other events might include racks, innings, fouls, time outs, etc. which each have their unique "set" of objects that need to be updated. This method will also be useful if I need to add new controls which I'm certain will occur.

With the above in mind, I decided to use the Tag property of each control and assign it a two letter code to indicate its collection grouping.

Now I just need to built the collections by looping through all controls in my solution, looking for the tag and assigning it to the appropriate named collection. Here's the little Tag Grouping array of possible tag values:
Public TG = New String() {"BR", "DB", "NS", "P1", "P2", "S1", "S2", "PM", "PN", "RI", "RN", "SS", "TM", "TN", "TO"}

Open in new window

I also have the following Function which I think might be useful for this task, but I'm not sure if it will grab everything:
    Public Shared Function getAllControls(ByVal CtlList As List(Of Control), ByVal parent As Control, ByVal CtlType As System.Type) As List(Of Control)
        If parent Is Nothing Then Return CtlList
        If parent.GetType Is CtlType Then CtlList.Add(parent)
        For Each child As Control In parent.Controls
            Call getAllControls(CtlList, child, CtlType)
        Next child
        Return CtlList
    End Function

Open in new window


Any assistance the Experts can provide with code examples would be greatly appreciated. Of course, if more information is needed, just let me know.

Thanks In Advance,
Tony Gardner
Comment
Watch Question

HainKurtSr. System Analyst
CERTIFIED EXPERT
Commented:
Unlock this solution and get a sample of our free trial.
(No credit card required)
UNLOCK SOLUTION
Tony GardnerSr. Programmer/Analyst

Author

Commented:
Thanks Huseyin, I've heard of LINQ but have never pursued learning it.

 We'll need a second expert's help to translate it to VB, and anything else I need to know to implement it.

Anyone?
HainKurtSr. System Analyst
CERTIFIED EXPERT

Commented:
you can test your code...
and check the number of controls or put trace/debug to see if it is working or not properly...

I saw that recursive code many times and used in my previous projects as well...
Fernando SotoRetired
CERTIFIED EXPERT
Distinguished Expert 2017

Commented:
@Huseyin, A minor correction on the Linq code you posted, you need to use the Lambda operator => where you are using >= in your code.
Fernando SotoRetired
CERTIFIED EXPERT
Distinguished Expert 2017
Commented:
Unlock this solution and get a sample of our free trial.
(No credit card required)
UNLOCK SOLUTION
Tony GardnerSr. Programmer/Analyst

Author

Commented:
Very intriguing solution, Fernando! Since I'm brand new to LINQ, I'm not sure that I understand what is occurring here.

For starters, is 'TB' supposed to be one of my Tags? If so, I'll substitute in one from the originally posted TG array.

When I do run it, I get the following exception:
System.InvalidCastException was unhandled
  HResult=-2147467262
  Message=Conversion from string "TB" to type 'Double' is not valid.
  Source=Microsoft.VisualBasic
  StackTrace:
       at Microsoft.VisualBasic.CompilerServices.Conversions.ToDouble(String Value, NumberFormatInfo NumberFormat)
       at Microsoft.VisualBasic.CompilerServices.Operators.CompareObject2(Object Left, Object Right, Boolean TextCompare)
       at Microsoft.VisualBasic.CompilerServices.Operators.ConditionalCompareObjectEqual(Object Left, Object Right, Boolean TextCompare)
       at SNAP.frmSNAP._Closure$__1._Lambda$__2(Control c) in C:\Users\tony.gardner\Documents\Visual Studio 2013\Projects\SNAP\SNAP\frmSnapMain.vb:line 161
       at System.Linq.Enumerable.WhereEnumerableIterator`1.MoveNext()
       at System.Linq.Enumerable.<SelectManyIterator>d__14`2.MoveNext()
       at System.Linq.Enumerable.<ConcatIterator>d__71`1.MoveNext()
       at System.Linq.Enumerable.WhereEnumerableIterator`1.MoveNext()
       at System.Linq.Enumerable.<SelectManyIterator>d__14`2.MoveNext()
       at System.Linq.Enumerable.<ConcatIterator>d__71`1.MoveNext()
       at System.Linq.Enumerable.WhereEnumerableIterator`1.MoveNext()
       at System.Linq.Enumerable.<SelectManyIterator>d__14`2.MoveNext()
       at System.Linq.Enumerable.<ConcatIterator>d__71`1.MoveNext()
       at System.Linq.Enumerable.WhereEnumerableIterator`1.MoveNext()
       at SNAP.frmSNAP.Init_Collections() in C:\Users\tony.gardner\Documents\Visual Studio 2013\Projects\SNAP\SNAP\frmSnapMain.vb:line 213
       at SNAP.frmSNAP.Initialize_Match() in C:\Users\tony.gardner\Documents\Visual Studio 2013\Projects\SNAP\SNAP\frmSnapMain.vb:line 199
       at SNAP.frmSNAP.tabMain_Enter(Object sender, EventArgs e) in C:\Users\tony.gardner\Documents\Visual Studio 2013\Projects\SNAP\SNAP\frmSnapMain.vb:line 363
       at System.Windows.Forms.Control.OnEnter(EventArgs e)
       at System.Windows.Forms.TabControl.OnEnter(EventArgs e)
       at System.Windows.Forms.Control.NotifyEnter()
       at System.Windows.Forms.ContainerControl.UpdateFocusedControl()
       at System.Windows.Forms.ContainerControl.AssignActiveControlInternal(Control value)
       at System.Windows.Forms.ContainerControl.ActivateControlInternal(Control control, Boolean originator)
       at System.Windows.Forms.ContainerControl.SetActiveControlInternal(Control value)
       at System.Windows.Forms.ContainerControl.set_ActiveControl(Control value)
       at System.Windows.Forms.Control.Select(Boolean directed, Boolean forward)
       at System.Windows.Forms.Control.SelectNextControl(Control ctl, Boolean forward, Boolean tabStopOnly, Boolean nested, Boolean wrap)
       at System.Windows.Forms.TabControl.UpdateTabSelection(Boolean updateFocus)
       at System.Windows.Forms.TabControl.OnSelectedIndexChanged(EventArgs e)
       at System.Windows.Forms.TabControl.WmSelChange()
       at System.Windows.Forms.TabControl.set_SelectedIndex(Int32 value)
       at System.Windows.Forms.TabControl.SelectTab(Int32 index)
       at SNAP.frmSNAP.pgSetupMatch_Enter(Object sender, EventArgs e) in C:\Users\tony.gardner\Documents\Visual Studio 2013\Projects\SNAP\SNAP\frmSnapMain.vb:line 940
       at System.Windows.Forms.Control.OnEnter(EventArgs e)
       at System.Windows.Forms.TabPage.OnEnter(EventArgs e)
       at System.Windows.Forms.TabPage.FireEnter(EventArgs e)
       at System.Windows.Forms.TabControl.OnSelected(TabControlEventArgs e)
       at System.Windows.Forms.TabControl.WmSelChange()
       at System.Windows.Forms.TabControl.WndProc(Message& m)
       at System.Windows.Forms.Control.ControlNativeWindow.OnMessage(Message& m)
       at System.Windows.Forms.Control.ControlNativeWindow.WndProc(Message& m)
       at System.Windows.Forms.NativeWindow.DebuggableCallback(IntPtr hWnd, Int32 msg, IntPtr wparam, IntPtr lparam)
       at System.Windows.Forms.UnsafeNativeMethods.SendMessage(HandleRef hWnd, Int32 msg, IntPtr wParam, IntPtr lParam)
       at System.Windows.Forms.Control.SendMessage(Int32 msg, IntPtr wparam, IntPtr lparam)
       at System.Windows.Forms.Control.ReflectMessageInternal(IntPtr hWnd, Message& m)
       at System.Windows.Forms.Control.WmNotify(Message& m)
       at System.Windows.Forms.Control.WndProc(Message& m)
       at System.Windows.Forms.ScrollableControl.WndProc(Message& m)
       at System.Windows.Forms.Form.WndProc(Message& m)
       at System.Windows.Forms.Control.ControlNativeWindow.OnMessage(Message& m)
       at System.Windows.Forms.Control.ControlNativeWindow.WndProc(Message& m)
       at System.Windows.Forms.NativeWindow.DebuggableCallback(IntPtr hWnd, Int32 msg, IntPtr wparam, IntPtr lparam)
       at System.Windows.Forms.UnsafeNativeMethods.CallWindowProc(IntPtr wndProc, IntPtr hWnd, Int32 msg, IntPtr wParam, IntPtr lParam)
       at System.Windows.Forms.NativeWindow.DefWndProc(Message& m)
       at System.Windows.Forms.Control.DefWndProc(Message& m)
       at System.Windows.Forms.Control.WmMouseUp(Message& m, MouseButtons button, Int32 clicks)
       at System.Windows.Forms.Control.WndProc(Message& m)
       at System.Windows.Forms.TabControl.WndProc(Message& m)
       at System.Windows.Forms.Control.ControlNativeWindow.OnMessage(Message& m)
       at System.Windows.Forms.Control.ControlNativeWindow.WndProc(Message& m)
       at System.Windows.Forms.NativeWindow.DebuggableCallback(IntPtr hWnd, Int32 msg, IntPtr wparam, IntPtr lparam)
       at System.Windows.Forms.UnsafeNativeMethods.DispatchMessageW(MSG& msg)
       at System.Windows.Forms.Application.ComponentManager.System.Windows.Forms.UnsafeNativeMethods.IMsoComponentManager.FPushMessageLoop(IntPtr dwComponentID, Int32 reason, Int32 pvLoopData)
       at System.Windows.Forms.Application.ThreadContext.RunMessageLoopInner(Int32 reason, ApplicationContext context)
       at System.Windows.Forms.Application.ThreadContext.RunMessageLoop(Int32 reason, ApplicationContext context)
       at System.Windows.Forms.Application.Run(ApplicationContext context)
       at Microsoft.VisualBasic.ApplicationServices.WindowsFormsApplicationBase.OnRun()
       at Microsoft.VisualBasic.ApplicationServices.WindowsFormsApplicationBase.DoApplicationModel()
       at Microsoft.VisualBasic.ApplicationServices.WindowsFormsApplicationBase.Run(String[] commandLine)
       at SNAP.My.MyApplication.Main(String[] Args) in 17d14f5c-a337-4978-8281-53493378c1071.vb:line 81
       at System.AppDomain._nExecuteAssembly(RuntimeAssembly assembly, String[] args)
       at System.AppDomain.ExecuteAssembly(String assemblyFile, Evidence assemblySecurity, String[] args)
       at Microsoft.VisualStudio.HostingProcess.HostProc.RunUsersAssembly()
       at System.Threading.ThreadHelper.ThreadStart_Context(Object state)
       at System.Threading.ExecutionContext.RunInternal(ExecutionContext executionContext, ContextCallback callback, Object state, Boolean preserveSyncCtx)
       at System.Threading.ExecutionContext.Run(ExecutionContext executionContext, ContextCallback callback, Object state, Boolean preserveSyncCtx)
       at System.Threading.ExecutionContext.Run(ExecutionContext executionContext, ContextCallback callback, Object state)
       at System.Threading.ThreadHelper.ThreadStart()
  InnerException: System.FormatException
       HResult=-2146233033
       Message=Input string was not in a correct format.
       Source=Microsoft.VisualBasic
       StackTrace:
            at Microsoft.VisualBasic.CompilerServices.Conversions.ParseDouble(String Value, NumberFormatInfo NumberFormat)
            at Microsoft.VisualBasic.CompilerServices.Conversions.ToDouble(String Value, NumberFormatInfo NumberFormat)
       InnerException: 

Open in new window


I also wanted to point out that not all objects will have tags. Others will have tags but not any within the TG array, so I hope that's not a huge problem. All tags in the TG array were assigned to the various buttons, labels, and other controls using the designer.
HainKurtSr. System Analyst
CERTIFIED EXPERT

Commented:
you should use the second version, provided by @Fernando
second parameter is string, not type/double as in the first version

Public Function GetAll(control As Control, tag As String) As IEnumerable(Of Control)                             
                                                                                                                
    Dim controls = control.Controls.Cast(Of Control)()                                                          
                                                                                                                
    Return controls.SelectMany(Function(ctrl) GetAll(ctrl, tag)).Concat(controls).Where(Function(c) c.Tag = tag)
                                                                                                                
End Function

Open in new window


the first version gives all controls that is a checkbox or text or radio etc...
whereas in the second version, you get all controls with same tag, regardless of type...
Fernando SotoRetired
CERTIFIED EXPERT
Distinguished Expert 2017

Commented:
Hi Tony;

To your question, "For starters, is 'TB' supposed to be one of my Tags?", Yes it is. So for example your array TG
Public TG = New String() {"BR", "DB", "NS", "P1", "P2", "S1", "S2", "PM", "PN", "RI", "RN", "SS", "TM", "TN", "TO"}

Open in new window

and lets say you want to query the controls for the 'NS' group then you call the function as follows
Dim nsGroup = GetAll(Me, TG(2))

Open in new window

To your question, "I also wanted to point out that not all objects will have tags. Others will have tags but not any within the TG array, so I hope that's not a huge problem" If tags are missing or the value of a tag is not in the array, not a problem.
Tony GardnerSr. Programmer/Analyst

Author

Commented:
This looked rock solid to me, so I tried creating the Group IDs using variable grpID into a loop to populate ALL collections in one fell swoop. Unfortunately, it's now complaining that 'BR' (the first item in the TG array) can't be converted to type Double. Obviously, it's somehow trying to assert the text over the array position. What I don't understand is that it should be using tagID as it's index. Perhaps you can spot my error:
    Private Sub Init_Collections()
        ' Public TG = New String() {"BR", "DB", "NS", "P1", "P2", "S1", "S2", "PM", "PN", "RI", "RN", "SS", "TM", "TN", "TO"}
        For tagID = 0 To TG.GetUpperBound(0)
            Dim grpID As String = "grp" & TG(tagID)
            Dim grpBR As IEnumerable = GetAll(Me, TG(tagID))
            For Each c In grpBR
                Debug.Print(c.Name)
            Next c
        Next
    End Sub

Open in new window


Here's my function definition (perhaps there's a typo in there):
    Public Function GetAll(control As Control, tag As String) As IEnumerable(Of Control)
        Dim controls = control.Controls.Cast(Of Control)()
        Return controls.SelectMany(Function(ctrl) GetAll(ctrl, tag)).Concat(controls).Where(Function(c) c.Tag = tag)
    End Function

Open in new window


Lastly, here is the full error text:
System.InvalidCastException was unhandled
  HResult=-2147467262
  Message=Conversion from string "BR" to type 'Double' is not valid.
  Source=Microsoft.VisualBasic
  StackTrace:
       at Microsoft.VisualBasic.CompilerServices.Conversions.ToDouble(String Value, NumberFormatInfo NumberFormat)
       at Microsoft.VisualBasic.CompilerServices.Operators.CompareObject2(Object Left, Object Right, Boolean TextCompare)
       at Microsoft.VisualBasic.CompilerServices.Operators.ConditionalCompareObjectEqual(Object Left, Object Right, Boolean TextCompare)
       at SNAP.frmSNAP._Closure$__1._Lambda$__2(Control c) in C:\Users\tony.gardner\Documents\Visual Studio 2013\Projects\SNAP\SNAP\frmSnapMain.vb:line 161
       at System.Linq.Enumerable.WhereEnumerableIterator`1.MoveNext()
       at System.Linq.Enumerable.<SelectManyIterator>d__14`2.MoveNext()
       at System.Linq.Enumerable.<ConcatIterator>d__71`1.MoveNext()
       at System.Linq.Enumerable.WhereEnumerableIterator`1.MoveNext()
       at System.Linq.Enumerable.<SelectManyIterator>d__14`2.MoveNext()
       at System.Linq.Enumerable.<ConcatIterator>d__71`1.MoveNext()
       at System.Linq.Enumerable.WhereEnumerableIterator`1.MoveNext()
       at System.Linq.Enumerable.<SelectManyIterator>d__14`2.MoveNext()
       at System.Linq.Enumerable.<ConcatIterator>d__71`1.MoveNext()
       at System.Linq.Enumerable.WhereEnumerableIterator`1.MoveNext()
       at SNAP.frmSNAP.Init_Collections() in C:\Users\tony.gardner\Documents\Visual Studio 2013\Projects\SNAP\SNAP\frmSnapMain.vb:line 216
       at SNAP.frmSNAP.Initialize_Match() in C:\Users\tony.gardner\Documents\Visual Studio 2013\Projects\SNAP\SNAP\frmSnapMain.vb:line 199
       at SNAP.frmSNAP.tabMain_Enter(Object sender, EventArgs e) in C:\Users\tony.gardner\Documents\Visual Studio 2013\Projects\SNAP\SNAP\frmSnapMain.vb:line 367
       at System.Windows.Forms.Control.OnEnter(EventArgs e)
       at System.Windows.Forms.TabControl.OnEnter(EventArgs e)
       at System.Windows.Forms.Control.NotifyEnter()
       at System.Windows.Forms.ContainerControl.UpdateFocusedControl()
       at System.Windows.Forms.ContainerControl.AssignActiveControlInternal(Control value)
       at System.Windows.Forms.ContainerControl.ActivateControlInternal(Control control, Boolean originator)
       at System.Windows.Forms.ContainerControl.SetActiveControlInternal(Control value)
       at System.Windows.Forms.TabControl.WmSelChanging()
       at System.Windows.Forms.TabControl.WndProc(Message& m)
       at System.Windows.Forms.Control.ControlNativeWindow.OnMessage(Message& m)
       at System.Windows.Forms.Control.ControlNativeWindow.WndProc(Message& m)
       at System.Windows.Forms.NativeWindow.DebuggableCallback(IntPtr hWnd, Int32 msg, IntPtr wparam, IntPtr lparam)
       at System.Windows.Forms.UnsafeNativeMethods.SendMessage(HandleRef hWnd, Int32 msg, IntPtr wParam, IntPtr lParam)
       at System.Windows.Forms.Control.SendMessage(Int32 msg, IntPtr wparam, IntPtr lparam)
       at System.Windows.Forms.Control.ReflectMessageInternal(IntPtr hWnd, Message& m)
       at System.Windows.Forms.Control.WmNotify(Message& m)
       at System.Windows.Forms.Control.WndProc(Message& m)
       at System.Windows.Forms.ScrollableControl.WndProc(Message& m)
       at System.Windows.Forms.Control.ControlNativeWindow.OnMessage(Message& m)
       at System.Windows.Forms.Control.ControlNativeWindow.WndProc(Message& m)
       at System.Windows.Forms.NativeWindow.DebuggableCallback(IntPtr hWnd, Int32 msg, IntPtr wparam, IntPtr lparam)
       at System.Windows.Forms.UnsafeNativeMethods.CallWindowProc(IntPtr wndProc, IntPtr hWnd, Int32 msg, IntPtr wParam, IntPtr lParam)
       at System.Windows.Forms.NativeWindow.DefWndProc(Message& m)
       at System.Windows.Forms.Control.DefWndProc(Message& m)
       at System.Windows.Forms.Control.WmMouseDown(Message& m, MouseButtons button, Int32 clicks)
       at System.Windows.Forms.Control.WndProc(Message& m)
       at System.Windows.Forms.TabControl.WndProc(Message& m)
       at System.Windows.Forms.Control.ControlNativeWindow.OnMessage(Message& m)
       at System.Windows.Forms.Control.ControlNativeWindow.WndProc(Message& m)
       at System.Windows.Forms.NativeWindow.DebuggableCallback(IntPtr hWnd, Int32 msg, IntPtr wparam, IntPtr lparam)
       at System.Windows.Forms.UnsafeNativeMethods.DispatchMessageW(MSG& msg)
       at System.Windows.Forms.Application.ComponentManager.System.Windows.Forms.UnsafeNativeMethods.IMsoComponentManager.FPushMessageLoop(IntPtr dwComponentID, Int32 reason, Int32 pvLoopData)
       at System.Windows.Forms.Application.ThreadContext.RunMessageLoopInner(Int32 reason, ApplicationContext context)
       at System.Windows.Forms.Application.ThreadContext.RunMessageLoop(Int32 reason, ApplicationContext context)
       at System.Windows.Forms.Application.Run(ApplicationContext context)
       at Microsoft.VisualBasic.ApplicationServices.WindowsFormsApplicationBase.OnRun()
       at Microsoft.VisualBasic.ApplicationServices.WindowsFormsApplicationBase.DoApplicationModel()
       at Microsoft.VisualBasic.ApplicationServices.WindowsFormsApplicationBase.Run(String[] commandLine)
       at SNAP.My.MyApplication.Main(String[] Args) in 17d14f5c-a337-4978-8281-53493378c1071.vb:line 81
       at System.AppDomain._nExecuteAssembly(RuntimeAssembly assembly, String[] args)
       at System.AppDomain.ExecuteAssembly(String assemblyFile, Evidence assemblySecurity, String[] args)
       at Microsoft.VisualStudio.HostingProcess.HostProc.RunUsersAssembly()
       at System.Threading.ThreadHelper.ThreadStart_Context(Object state)
       at System.Threading.ExecutionContext.RunInternal(ExecutionContext executionContext, ContextCallback callback, Object state, Boolean preserveSyncCtx)
       at System.Threading.ExecutionContext.Run(ExecutionContext executionContext, ContextCallback callback, Object state, Boolean preserveSyncCtx)
       at System.Threading.ExecutionContext.Run(ExecutionContext executionContext, ContextCallback callback, Object state)
       at System.Threading.ThreadHelper.ThreadStart()
  InnerException: System.FormatException
       HResult=-2146233033
       Message=Input string was not in a correct format.
       Source=Microsoft.VisualBasic
       StackTrace:
            at Microsoft.VisualBasic.CompilerServices.Conversions.ParseDouble(String Value, NumberFormatInfo NumberFormat)
            at Microsoft.VisualBasic.CompilerServices.Conversions.ToDouble(String Value, NumberFormatInfo NumberFormat)
       InnerException: 

Open in new window


Thanks everyone in advance for your assistance!
Fernando SotoRetired
CERTIFIED EXPERT
Distinguished Expert 2017

Commented:
First try changing this line of code
 Public TG = New String() {"BR", "DB", "NS", "P1", "P2", "S1", "S2", "PM", "PN", "RI", "RN", "SS", "TM", "TN", "TO"}

Open in new window

to this
 Public TG As String() = New String() {"BR", "DB", "NS", "P1", "P2", "S1", "S2", "PM", "PN", "RI", "RN", "SS", "TM", "TN", "TO"}

Open in new window

Fernando SotoRetired
CERTIFIED EXPERT
Distinguished Expert 2017

Commented:
Also on what line of code is the program throwing the exception on. I have placed you code into a project and it compiles with no errors.
HainKurtSr. System Analyst
CERTIFIED EXPERT

Commented:
what are those lines in the message...

message do not tell too much without corresponding line...

frmSnapMain.vb:line 161
frmSnapMain.vb:line 216
frmSnapMain.vb:line 199
frmSnapMain.vb:line 367

best attach full code :)
Tony GardnerSr. Programmer/Analyst

Author

Commented:
Here's a screen shot:
Screen Shot of error message from GetAll function
The error occurs on Line 162, which reads as follows:
Return controls.SelectMany(Function(ctrl) GetAll(ctrl, tag)).Concat(controls).Where(Function(c) c.Tag = tag)

Open in new window


Note that I did make the change to the TG declaration as follows:
Public TG As String() = New String() {"BR", "DB", "NS", "P1", "P2", "S1", "S2", "PM", "PN", "RI", "RN", "SS", "TM", "TN", "TO"}

Open in new window


I'm very much hoping to avoid posting the entire Solution given that we don't have a non-disclosure agreement (not you could ever benefit from my newbie coding!).

So, I hope this will suffice for now.
Fernando SotoRetired
CERTIFIED EXPERT
Distinguished Expert 2017

Commented:
Please try changing this line of code
Return controls.SelectMany(Function(ctrl) GetAll(ctrl, tag)).Concat(controls).Where(Function(c) c.Tag = tag)

Open in new window

to this
Return controls.SelectMany(Function(ctrl) GetAll(ctrl, tag)).Concat(controls).Where(Function(c) c.Tag.ToString() = tag)

Open in new window

Fernando SotoRetired
CERTIFIED EXPERT
Distinguished Expert 2017

Commented:
Also how are you setting the Tag property in the control, via the Form's property page, if so are you entering something like BR or are you using "BR"?
Tony GardnerSr. Programmer/Analyst

Author

Commented:
With the ToString added, we are now getting a different error:
System.NullReferenceException was unhandled
  HResult=-2147467261
  Message=Object reference not set to an instance of an object.
  Source=SNAP
  StackTrace:
       at SNAP.frmSNAP._Closure$__1._Lambda$__2(Control c) in C:\Users\tony.gardner\Documents\Visual Studio 2013\Projects\SNAP\SNAP\frmSnapMain.vb:line 163
       at System.Linq.Enumerable.WhereEnumerableIterator`1.MoveNext()
       at System.Linq.Enumerable.<SelectManyIterator>d__14`2.MoveNext()
       at System.Linq.Enumerable.<ConcatIterator>d__71`1.MoveNext()
       at System.Linq.Enumerable.WhereEnumerableIterator`1.MoveNext()
       at System.Linq.Enumerable.<SelectManyIterator>d__14`2.MoveNext()
       at System.Linq.Enumerable.<ConcatIterator>d__71`1.MoveNext()
       at System.Linq.Enumerable.WhereEnumerableIterator`1.MoveNext()
       at SNAP.frmSNAP.Init_Collections() in C:\Users\tony.gardner\Documents\Visual Studio 2013\Projects\SNAP\SNAP\frmSnapMain.vb:line 219
       at SNAP.frmSNAP.Initialize_Match() in C:\Users\tony.gardner\Documents\Visual Studio 2013\Projects\SNAP\SNAP\frmSnapMain.vb:line 202
       at SNAP.frmSNAP.tabMain_Enter(Object sender, EventArgs e) in C:\Users\tony.gardner\Documents\Visual Studio 2013\Projects\SNAP\SNAP\frmSnapMain.vb:line 370
       at System.Windows.Forms.Control.OnEnter(EventArgs e)
       at System.Windows.Forms.TabControl.OnEnter(EventArgs e)
       at System.Windows.Forms.Control.NotifyEnter()
       at System.Windows.Forms.ContainerControl.UpdateFocusedControl()
       at System.Windows.Forms.ContainerControl.AssignActiveControlInternal(Control value)
       at System.Windows.Forms.ContainerControl.ActivateControlInternal(Control control, Boolean originator)
       at System.Windows.Forms.ContainerControl.SetActiveControlInternal(Control value)
       at System.Windows.Forms.TabControl.WmSelChanging()
       at System.Windows.Forms.TabControl.WndProc(Message& m)
       at System.Windows.Forms.Control.ControlNativeWindow.OnMessage(Message& m)
       at System.Windows.Forms.Control.ControlNativeWindow.WndProc(Message& m)
       at System.Windows.Forms.NativeWindow.DebuggableCallback(IntPtr hWnd, Int32 msg, IntPtr wparam, IntPtr lparam)
       at System.Windows.Forms.UnsafeNativeMethods.SendMessage(HandleRef hWnd, Int32 msg, IntPtr wParam, IntPtr lParam)
       at System.Windows.Forms.Control.SendMessage(Int32 msg, IntPtr wparam, IntPtr lparam)
       at System.Windows.Forms.Control.ReflectMessageInternal(IntPtr hWnd, Message& m)
       at System.Windows.Forms.Control.WmNotify(Message& m)
       at System.Windows.Forms.Control.WndProc(Message& m)
       at System.Windows.Forms.ScrollableControl.WndProc(Message& m)
       at System.Windows.Forms.Control.ControlNativeWindow.OnMessage(Message& m)
       at System.Windows.Forms.Control.ControlNativeWindow.WndProc(Message& m)
       at System.Windows.Forms.NativeWindow.DebuggableCallback(IntPtr hWnd, Int32 msg, IntPtr wparam, IntPtr lparam)
       at System.Windows.Forms.UnsafeNativeMethods.CallWindowProc(IntPtr wndProc, IntPtr hWnd, Int32 msg, IntPtr wParam, IntPtr lParam)
       at System.Windows.Forms.NativeWindow.DefWndProc(Message& m)
       at System.Windows.Forms.Control.DefWndProc(Message& m)
       at System.Windows.Forms.Control.WmMouseDown(Message& m, MouseButtons button, Int32 clicks)
       at System.Windows.Forms.Control.WndProc(Message& m)
       at System.Windows.Forms.TabControl.WndProc(Message& m)
       at System.Windows.Forms.Control.ControlNativeWindow.OnMessage(Message& m)
       at System.Windows.Forms.Control.ControlNativeWindow.WndProc(Message& m)
       at System.Windows.Forms.NativeWindow.DebuggableCallback(IntPtr hWnd, Int32 msg, IntPtr wparam, IntPtr lparam)
       at System.Windows.Forms.UnsafeNativeMethods.DispatchMessageW(MSG& msg)
       at System.Windows.Forms.Application.ComponentManager.System.Windows.Forms.UnsafeNativeMethods.IMsoComponentManager.FPushMessageLoop(IntPtr dwComponentID, Int32 reason, Int32 pvLoopData)
       at System.Windows.Forms.Application.ThreadContext.RunMessageLoopInner(Int32 reason, ApplicationContext context)
       at System.Windows.Forms.Application.ThreadContext.RunMessageLoop(Int32 reason, ApplicationContext context)
       at System.Windows.Forms.Application.Run(ApplicationContext context)
       at Microsoft.VisualBasic.ApplicationServices.WindowsFormsApplicationBase.OnRun()
       at Microsoft.VisualBasic.ApplicationServices.WindowsFormsApplicationBase.DoApplicationModel()
       at Microsoft.VisualBasic.ApplicationServices.WindowsFormsApplicationBase.Run(String[] commandLine)
       at SNAP.My.MyApplication.Main(String[] Args) in 17d14f5c-a337-4978-8281-53493378c1071.vb:line 81
       at System.AppDomain._nExecuteAssembly(RuntimeAssembly assembly, String[] args)
       at System.AppDomain.ExecuteAssembly(String assemblyFile, Evidence assemblySecurity, String[] args)
       at Microsoft.VisualStudio.HostingProcess.HostProc.RunUsersAssembly()
       at System.Threading.ThreadHelper.ThreadStart_Context(Object state)
       at System.Threading.ExecutionContext.RunInternal(ExecutionContext executionContext, ContextCallback callback, Object state, Boolean preserveSyncCtx)
       at System.Threading.ExecutionContext.Run(ExecutionContext executionContext, ContextCallback callback, Object state, Boolean preserveSyncCtx)
       at System.Threading.ExecutionContext.Run(ExecutionContext executionContext, ContextCallback callback, Object state)
       at System.Threading.ThreadHelper.ThreadStart()
  InnerException: 

Open in new window


Same line as before.

Each control's .Tag property is being set without quotes.
HainKurtSr. System Analyst
CERTIFIED EXPERT

Commented:
also, make a favor and turn on line numbers

To display line numbers in code. On the menu bar, choose Tools, Options. Expand the Text Editor node, and then select either the node for the
language you are using, or All Languages to turn on line numbers in all languages. Or you can type line number in the Quick Launch box.

Note:
Depending on your language or settings, you may have to select the Show All Settings check box in the Options dialog box to reveal the All Languages sub-node.
IC612369.jpeg
HainKurtSr. System Analyst
CERTIFIED EXPERT

Commented:
you may use

if(comp.tag Is Nothing, "", comp.tag.toString())

or

iif(comp.tag Is Nothing, "", comp.tag.toString())
Fernando SotoRetired
CERTIFIED EXPERT
Distinguished Expert 2017

Commented:
I can't see why that error is happening. Can you please put together a test project with a form and a couple of controls setting it up like in your actual project with the GetAll function and the array. if you are getting the same error please zip that test project completely and post to a public folder such as OneDrive or DropBox on the web where we can download it and test it.
it_saigeDeveloper
CERTIFIED EXPERT
Distinguished Expert 2019

Commented:
*NO POINTS*

Fernando and Huseyin are both on the right track.  To make the overall solution a little more easier to work with, I would make the following enhancements.

1.  Use a well defined type as your TagType as opposed to a string or string array; e.g. - An enumeration:
Enum TagType
    BR = 0
    DB
    NS
    P1
    P2
    S1
    S2
    PM
    PN
    RI
    RN
    SS
    TM
    TN
    [TO]
End Enum

Open in new window


2.  Use a dictionary to store your groupings; e.g. -
ReadOnly tagged As New Dictionary(Of TagType, IEnumerable(Of Control))

Open in new window


These enhancements would require the following change to the proposed GetAll method -
Module Extensions
    <Extension()>
    Public Function GetAll(control As Control, tag As TagType) As IEnumerable(Of Control)
        Return control.Controls.Cast(Of Control) _
        .SelectMany(Function(ctrl) GetAll(ctrl, tag)) _
        .Concat(control.Controls.Cast(Of Control)) _
        .Where(Function(c) TypeOf c IsNot Form _
            AndAlso c.Tag IsNot Nothing _
            AndAlso TypeOf c.Tag Is TagType _
            AndAlso CType(c.Tag, TagType).Equals(tag))
    End Function
End Module

Open in new window


Full proof of concept -

Form1.vb -
Imports System.Runtime.CompilerServices

Public Class Form1
    ReadOnly tagged As New Dictionary(Of TagType, IEnumerable(Of Control))

    Public Sub New()
        InitializeComponent()
        Dim c As Control = Nothing
        ' Populate form with some tagged controls
        For i = 0 To 4
            For Each t As TagType In GetType(TagType).GetEnumValues
                If i = 0 Then
                    c = New Label() With {
                        .Name = String.Format("Label{0}", CType(t, Integer)),
                        .Tag = t,
                        .Text = Name
                    }
                ElseIf i = 1 Then
                    c = New ListBox() With {
                        .Name = String.Format("ListBox{0}", CType(t, Integer)),
                        .Tag = t,
                        .Text = Name
                    }
                ElseIf i = 2 Then
                    c = New TextBox() With {
                        .Name = String.Format("TextBox{0}", CType(t, Integer)),
                        .Tag = t,
                        .Text = Name
                    }
                ElseIf i = 3 Then
                    c = New CheckBox() With {
                        .Name = String.Format("CheckBox{0}", CType(t, Integer)),
                        .Tag = t,
                        .Text = Name
                    }
                Else
                End If
                If c IsNot Nothing Then Panel1.Controls.Add(c)
            Next
        Next
    End Sub

    Private Sub OnLoad(sender As Object, e As EventArgs) Handles MyBase.Load
        For Each t As TagType In GetType(TagType).GetEnumValues
            tagged.Add(t, Me.GetAll(t))
        Next
        ListBox1.DataSource = GetType(TagType).GetEnumNames
    End Sub

    Private Sub OnSelectedValueChanged(sender As Object, e As EventArgs) Handles ListBox1.SelectedValueChanged
        With TreeView1
            .BeginUpdate()
            .Nodes.Clear()
            Dim parent As New TreeNode(CType(sender, ListBox).SelectedItem,
                                       (From c In tagged([Enum].Parse(GetType(TagType), CType(sender, ListBox).SelectedItem))
                                        Select New TreeNode(c.Name,
                                            (From p In c.GetType.GetProperties()
                                             Select New TreeNode(String.Format("{0} = {1}",
                                                 p.Name,
                                                 p.GetValue(c, Nothing)))) _
                                            .ToArray())) _
                                        .ToArray())
            .Nodes.Add(parent)
            .EndUpdate()
        End With
    End Sub
End Class

Enum TagType
    BR = 0
    DB
    NS
    P1
    P2
    S1
    S2
    PM
    PN
    RI
    RN
    SS
    TM
    TN
    [TO]
End Enum

Module Extensions
    <Extension()>
    Public Function GetAll(control As Control, tag As TagType) As IEnumerable(Of Control)
        Return control.Controls.Cast(Of Control) _
        .SelectMany(Function(ctrl) GetAll(ctrl, tag)) _
        .Concat(control.Controls.Cast(Of Control)) _
        .Where(Function(c) TypeOf c IsNot Form _
            AndAlso c.Tag IsNot Nothing _
            AndAlso TypeOf c.Tag Is TagType _
            AndAlso CType(c.Tag, TagType).Equals(tag))
    End Function
End Module

Open in new window


Form1.Designer.vb -
<Global.Microsoft.VisualBasic.CompilerServices.DesignerGenerated()> _
Partial Class Form1
    Inherits System.Windows.Forms.Form

    'Form overrides dispose to clean up the component list.
    <System.Diagnostics.DebuggerNonUserCode()> _
    Protected Overrides Sub Dispose(ByVal disposing As Boolean)
        Try
            If disposing AndAlso components IsNot Nothing Then
                components.Dispose()
            End If
        Finally
            MyBase.Dispose(disposing)
        End Try
    End Sub

    'Required by the Windows Form Designer
    Private components As System.ComponentModel.IContainer

    'NOTE: The following procedure is required by the Windows Form Designer
    'It can be modified using the Windows Form Designer.  
    'Do not modify it using the code editor.
    <System.Diagnostics.DebuggerStepThrough()> _
    Private Sub InitializeComponent()
        Me.ListBox1 = New System.Windows.Forms.ListBox()
        Me.Panel1 = New System.Windows.Forms.Panel()
        Me.TreeView1 = New System.Windows.Forms.TreeView()
        Me.SuspendLayout()
        '
        'ListBox1
        '
        Me.ListBox1.Dock = System.Windows.Forms.DockStyle.Left
        Me.ListBox1.FormattingEnabled = True
        Me.ListBox1.Location = New System.Drawing.Point(200, 0)
        Me.ListBox1.Name = "ListBox1"
        Me.ListBox1.Size = New System.Drawing.Size(197, 439)
        Me.ListBox1.TabIndex = 0
        '
        'Panel1
        '
        Me.Panel1.Dock = System.Windows.Forms.DockStyle.Left
        Me.Panel1.Location = New System.Drawing.Point(0, 0)
        Me.Panel1.Name = "Panel1"
        Me.Panel1.Size = New System.Drawing.Size(200, 439)
        Me.Panel1.TabIndex = 1
        '
        'TreeView1
        '
        Me.TreeView1.Dock = System.Windows.Forms.DockStyle.Fill
        Me.TreeView1.Location = New System.Drawing.Point(397, 0)
        Me.TreeView1.Name = "TreeView1"
        Me.TreeView1.Size = New System.Drawing.Size(265, 439)
        Me.TreeView1.TabIndex = 2
        '
        'Form1
        '
        Me.AutoScaleDimensions = New System.Drawing.SizeF(6.0!, 13.0!)
        Me.AutoScaleMode = System.Windows.Forms.AutoScaleMode.Font
        Me.ClientSize = New System.Drawing.Size(662, 439)
        Me.Controls.Add(Me.TreeView1)
        Me.Controls.Add(Me.ListBox1)
        Me.Controls.Add(Me.Panel1)
        Me.Name = "Form1"
        Me.Text = "Form1"
        Me.ResumeLayout(False)

    End Sub

    Friend WithEvents ListBox1 As ListBox
    Friend WithEvents Panel1 As Panel
    Friend WithEvents TreeView1 As TreeView
End Class

Open in new window


Produces the following output -
Initial load -Capture.PNGSelecting a TagType; e.g. 'RI'-Capture.PNGExpanding the controls that are in the associated collection -Capture.PNG
-saige-
Tony GardnerSr. Programmer/Analyst

Author

Commented:
@it_saige:
Thanks so much for jumping in and helping out with your revised solution. I went ahead an implemented everything you prescribed into my project, and am VERY close. I seem to be getting an error on the line which says
.Where(Function(c) TypeOf c IsNot Form _

Open in new window

You can see that It is complaining about the word 'Form' in the following screen shot:
GetAll Error
Any thoughts why that might be happening? You might also notice that it doesn't like the "IsNot" just prior to the word "Form", so that might be something to consider as well.
it_saigeDeveloper
CERTIFIED EXPERT
Distinguished Expert 2019

Commented:
Either add an Imports System.Windows.Forms in the imports section of your file, or explicitly define the namespace/dependency; e.g. -
Module Extensions
    <Extension()>
    Public Function GetAll(control As Control, tag As TagType) As IEnumerable(Of Control)
        Return control.Controls.Cast(Of Control) _
        .SelectMany(Function(ctrl) GetAll(ctrl, tag)) _
        .Concat(control.Controls.Cast(Of Control)) _
        .Where(Function(c) TypeOf c IsNot System.Windows.Forms.Form _
            AndAlso c.Tag IsNot Nothing _
            AndAlso TypeOf c.Tag Is TagType _
            AndAlso CType(c.Tag, TagType).Equals(tag))
    End Function
End Module

Open in new window


The reason that the design-time compiler is barking at IsNot is because IsNot is expected to be used on a reference type.  Since the 'Form' type is unknown, the design-time compiler cannot verify that IsNot's usage is legal.  Once you either add the import or explicitly define the namespace/dependency, then the errors should go away.

This is all based on the assumption that your root design-time control is a System.Windows.Forms.Form instance and not some other third-party form control; e.g. - DevExpress' MetroForm.  If that is the case, then change the Form reference to whatever super-type your third-party form control inherits from.

-saige-
HainKurtSr. System Analyst
CERTIFIED EXPERT

Commented:
maybe you can use

not TypeOf c is System.Windows.Forms.Form
Tony GardnerSr. Programmer/Analyst

Author

Commented:
I'm sure you can imagine how a 6th grader would respond to PhD level information. In fact I think I'm more like a 6th grade caveman trying to understand particle physics. Well, at least I know how to read and do basic math! Okay, moving on...

I believe I was able to take a "shortcut" to solving our little dilemma by hard-coding my one and only form into the Function:
Module Extensions
    <Extension()>
    Public Function GetAll(control As Control, tag As TagType) As IEnumerable(Of Control)
        Return control.Controls.Cast(Of Control) _
        .SelectMany(Function(ctrl) GetAll(ctrl, tag)) _
        .Concat(control.Controls.Cast(Of Control)) _
        .Where(Function(c) TypeName(c) IsNot frmSNAP _
            AndAlso c.Tag IsNot Nothing _
            AndAlso TypeOf c.Tag Is TagType _
            AndAlso CType(c.Tag, TagType).Equals(tag))
    End Function
End Module

Open in new window

Please let me know if this is completely off-base, or is an acceptable way to for us to move on.

I realize that this Question has gone MUCH longer than any of us would have anticipated, so I'm hoping this last clarification point is reasonable.

If I understand correctly, the only remaining step is for me to build the collections. I see in the provided Private Sub OnLoad that the objects are being added to the tagged Dictionary. I guess I just need to learn how to practically get one of the collections that I can loop through.

At this point, I am okay either with doing something similar to my originally provided Init_Collections sub or just getting one set that For Each or other looping method would support.
it_saigeDeveloper
CERTIFIED EXPERT
Distinguished Expert 2019

Commented:
If it works then who are we to argue.  In reality the check itself is a moot point because the form should not have a Tag set to a TagType which would filter the inclusion of the base form.  So we can actually remove the check; e.g. -
Module Extensions
    <Extension()>
    Public Function GetAll(control As Control, tag As TagType) As IEnumerable(Of Control)
        Return control.Controls.Cast(Of Control) _
        .SelectMany(Function(ctrl) GetAll(ctrl, tag)) _
        .Concat(control.Controls.Cast(Of Control)) _
        .Where(Function(c) c.Tag IsNot Nothing _
            AndAlso TypeOf c.Tag Is TagType _
            AndAlso CType(c.Tag, TagType).Equals(tag))
    End Function
End Module

Open in new window

Would give the exact same output as the provided example.

As for your follow-up question, that is correct, you only need to build the collections.  The benefit of using a dictionary is that you can easily retrieve the collection of controls based on their tag value without needing to reiterate the entire controls collection; e.g. -
Dim brControls = tagged(TagType.BR)

Open in new window

Or storing a multitude of collections (one for each tagtype).

Proof of concept -

Form1.vb -
Imports System.Reflection
Imports System.Runtime.CompilerServices

Public Class Form1
    ReadOnly tagged As New Dictionary(Of TagType, IEnumerable(Of Control))

    Public Sub New()
        InitializeComponent()
        Dim c As Control = Nothing
        ' Populate form with some tagged controls
        For i = 0 To 4
            For Each t As TagType In GetType(TagType).GetEnumValues
                If i = 0 Then
                    c = New Label() With {
                        .Name = String.Format("Label{0}", CType(t, Integer)),
                        .Tag = t,
                        .Text = Name
                    }
                ElseIf i = 1 Then
                    c = New ListBox() With {
                        .Name = String.Format("ListBox{0}", CType(t, Integer)),
                        .Tag = t,
                        .Text = Name
                    }
                ElseIf i = 2 Then
                    c = New TextBox() With {
                        .Name = String.Format("TextBox{0}", CType(t, Integer)),
                        .Tag = t,
                        .Text = Name
                    }
                ElseIf i = 3 Then
                    c = New CheckBox() With {
                        .Name = String.Format("CheckBox{0}", CType(t, Integer)),
                        .Tag = t,
                        .Text = Name
                    }
                Else
                End If
                If c IsNot Nothing Then Panel1.Controls.Add(c)
            Next
        Next
    End Sub

    Private Sub OnLoad(sender As Object, e As EventArgs) Handles MyBase.Load
        For Each t As TagType In GetType(TagType).GetEnumValues
            tagged.Add(t, Me.GetAll(t))
        Next
        ListBox1.DataSource = GetType(TagType).GetEnumNames
        ComboBox1.DataSource = GetType(TagType).GetEnumValues
    End Sub

    Private Sub OnSelectedValueChanged(sender As Object, e As EventArgs) Handles ListBox1.SelectedValueChanged
        With TreeView1
            .BeginUpdate()
            .Nodes.Clear()
            Dim parent As New TreeNode(CType(sender, ListBox).SelectedItem,
                                       (From c In tagged([Enum].Parse(GetType(TagType), CType(sender, ListBox).SelectedItem))
                                        Select New TreeNode(c.Name,
                                            (From p In c.GetType.GetProperties()
                                             Select New TreeNode(String.Format("{0} = {1}",
                                                 p.Name,
                                                 p.GetValue(c, Nothing)))) _
                                            .ToArray())) _
                                        .ToArray())
            .Nodes.Add(parent)
            .EndUpdate()
        End With
    End Sub

    Private Sub OnClick(sender As Object, e As EventArgs) Handles Button1.Click
        Dim tag = CType(ComboBox1.SelectedValue, TagType)
        With TreeView1
            .BeginUpdate()
            .Nodes.Clear()
            Dim parent As New TreeNode(tag.ToString())
            If parent IsNot Nothing Then
                For Each c As Control In tagged(tag)
                    Dim child As New TreeNode(c.Name)
                    For Each p As PropertyInfo In c.GetType.GetProperties()
                        Dim pair As New TreeNode(String.Format("{0} = {1}", p.Name, p.GetValue(c, Nothing)))
                        If pair IsNot Nothing Then child.Nodes.Add(pair)
                    Next
                    If child IsNot Nothing Then parent.Nodes.Add(child)
                Next
            End If
            If parent IsNot Nothing Then .Nodes.Add(parent)
            .EndUpdate()
        End With
    End Sub
End Class

Enum TagType
    BR = 0
    DB
    NS
    P1
    P2
    S1
    S2
    PM
    PN
    RI
    RN
    SS
    TM
    TN
    [TO]
End Enum

Module Extensions
    <Extension()>
    Public Function GetAll(control As Control, tag As TagType) As IEnumerable(Of Control)
        Return control.Controls.Cast(Of Control) _
        .SelectMany(Function(ctrl) GetAll(ctrl, tag)) _
        .Concat(control.Controls.Cast(Of Control)) _
        .Where(Function(c) c.Tag IsNot Nothing _
            AndAlso TypeOf c.Tag Is TagType _
            AndAlso CType(c.Tag, TagType).Equals(tag))
    End Function
End Module

Open in new window


Form1.Designer.vb -
<Global.Microsoft.VisualBasic.CompilerServices.DesignerGenerated()>
Partial Class Form1
    Inherits System.Windows.Forms.Form

    'Form overrides dispose to clean up the component list.
    <System.Diagnostics.DebuggerNonUserCode()>
    Protected Overrides Sub Dispose(ByVal disposing As Boolean)
        Try
            If disposing AndAlso components IsNot Nothing Then
                components.Dispose()
            End If
        Finally
            MyBase.Dispose(disposing)
        End Try
    End Sub

    'Required by the Windows Form Designer
    Private components As System.ComponentModel.IContainer

    'NOTE: The following procedure is required by the Windows Form Designer
    'It can be modified using the Windows Form Designer.  
    'Do not modify it using the code editor.
    <System.Diagnostics.DebuggerStepThrough()>
    Private Sub InitializeComponent()
        Me.ListBox1 = New System.Windows.Forms.ListBox()
        Me.Panel1 = New System.Windows.Forms.Panel()
        Me.TreeView1 = New System.Windows.Forms.TreeView()
        Me.ComboBox1 = New System.Windows.Forms.ComboBox()
        Me.Button1 = New System.Windows.Forms.Button()
        Me.Panel1.SuspendLayout()
        Me.SuspendLayout()
        '
        'ListBox1
        '
        Me.ListBox1.Dock = System.Windows.Forms.DockStyle.Left
        Me.ListBox1.FormattingEnabled = True
        Me.ListBox1.Location = New System.Drawing.Point(200, 0)
        Me.ListBox1.Name = "ListBox1"
        Me.ListBox1.Size = New System.Drawing.Size(197, 439)
        Me.ListBox1.TabIndex = 0
        '
        'Panel1
        '
        Me.Panel1.Controls.Add(Me.Button1)
        Me.Panel1.Controls.Add(Me.ComboBox1)
        Me.Panel1.Dock = System.Windows.Forms.DockStyle.Left
        Me.Panel1.Location = New System.Drawing.Point(0, 0)
        Me.Panel1.Name = "Panel1"
        Me.Panel1.Size = New System.Drawing.Size(200, 439)
        Me.Panel1.TabIndex = 1
        '
        'TreeView1
        '
        Me.TreeView1.Dock = System.Windows.Forms.DockStyle.Fill
        Me.TreeView1.Location = New System.Drawing.Point(397, 0)
        Me.TreeView1.Name = "TreeView1"
        Me.TreeView1.Size = New System.Drawing.Size(265, 439)
        Me.TreeView1.TabIndex = 2
        '
        'ComboBox1
        '
        Me.ComboBox1.FormattingEnabled = True
        Me.ComboBox1.Location = New System.Drawing.Point(13, 406)
        Me.ComboBox1.Name = "ComboBox1"
        Me.ComboBox1.Size = New System.Drawing.Size(74, 21)
        Me.ComboBox1.TabIndex = 0
        '
        'Button1
        '
        Me.Button1.Location = New System.Drawing.Point(93, 406)
        Me.Button1.Name = "Button1"
        Me.Button1.Size = New System.Drawing.Size(104, 23)
        Me.Button1.TabIndex = 1
        Me.Button1.Text = "Show Controls"
        Me.Button1.UseVisualStyleBackColor = True
        '
        'Form1
        '
        Me.AutoScaleDimensions = New System.Drawing.SizeF(6.0!, 13.0!)
        Me.AutoScaleMode = System.Windows.Forms.AutoScaleMode.Font
        Me.ClientSize = New System.Drawing.Size(662, 439)
        Me.Controls.Add(Me.TreeView1)
        Me.Controls.Add(Me.ListBox1)
        Me.Controls.Add(Me.Panel1)
        Me.Name = "Form1"
        Me.Text = "Form1"
        Me.Panel1.ResumeLayout(False)
        Me.ResumeLayout(False)

    End Sub

    Friend WithEvents ListBox1 As ListBox
    Friend WithEvents Panel1 As Panel
    Friend WithEvents TreeView1 As TreeView
    Friend WithEvents ComboBox1 As ComboBox
    Friend WithEvents Button1 As Button
End Class

Open in new window


Produces the following output -

Notice the dropdown -Capture.PNGIf we select an item and click the button; the treeview gets updated -Capture.PNG
I took the original method and expanded it out a bit so that you could see the relationship with what it is doing; e.g. -
Private Sub OnClick(sender As Object, e As EventArgs) Handles Button1.Click
    Dim tag = CType(ComboBox1.SelectedValue, TagType)
    With TreeView1
        .BeginUpdate()
        .Nodes.Clear()
        Dim parent As New TreeNode(tag.ToString())
        If parent IsNot Nothing Then
            For Each c As Control In tagged(tag)
                Dim child As New TreeNode(c.Name)
                For Each p As PropertyInfo In c.GetType.GetProperties()
                    Dim pair As New TreeNode(String.Format("{0} = {1}", _
                                                            p.Name, _
                                                            p.GetValue(c, Nothing)))
                    If pair IsNot Nothing Then child.Nodes.Add(pair)
                Next
                If child IsNot Nothing Then parent.Nodes.Add(child)
            Next
        End If
        If parent IsNot Nothing Then .Nodes.Add(parent)
        .EndUpdate()
    End With
End Sub

Open in new window


Either way it is up to you as you have to support the final implementation.  Just know that there are many ways to accomplish the same thing and much like a 6th grader responding to PhD level information, we can always disseminate the information into a format that can be understood by all parties.

-saige-
Tony GardnerSr. Programmer/Analyst

Author

Commented:
Well, I finally took the time to make a super simple example which should clearly demonstrate what it is I'm trying to do.

I've implemented as much code as I could comprehend, and I'm hoping The Experts can help fill in the blanks.

I'm pretty sure at this point we've established a new record for keeping a question open!

Kind Regards,
Tony Gardner
Demonstration1.ZIP
Fernando SotoRetired
CERTIFIED EXPERT
Distinguished Expert 2017

Commented:
Hi Tony;

You state the following, "Well, I finally took the time to make a super simple example which should clearly demonstrate what it is I'm trying to do.", I'am sorry but this project is not clear to me. For example this line of code
Dim CT = GetObject("TagType." & sender.Tag)

Open in new window

the GetObject function is a com component function which according to the Microsoft documentation
Use the GetObject function to load an instance of a COM component from a file
Where the first parameter, PathName :  Optional. String. The full path and name of the file containing the object to retrieve. If PathName is omitted or is a zero-length string (""), Class is required.
the second parameter, Class : Required if PathName is not supplied. String. A string representing the class of the object.
The other thing is that the function GetAll is never being used and so how do we determine where the issues are?
Developer
CERTIFIED EXPERT
Distinguished Expert 2019
Commented:
Unlock this solution and get a sample of our free trial.
(No credit card required)
UNLOCK SOLUTION
Tony GardnerSr. Programmer/Analyst

Author

Commented:
@Saige - I'm ready to close this Question, but wanted to check in with you first. When you joined the conversation you posted "* No Points *". Did that mean I should not include you in the distribution of points for answering this question??? Either way, I'm very thankful for your time and patience!
it_saigeDeveloper
CERTIFIED EXPERT
Distinguished Expert 2019

Commented:
I think it would be fair to split the bulk of the points between Fernando and Huseyin as they provided the original solution and then award a small amount to me for the enhancements.  Either way if Fernando and/or Huseyin would like to chime in on what would be a fair distribution, I would allow them some time to do so.

Regardless of the points distribution make sure you chose the correct comment as your solution.

-saige-
Fernando SotoRetired
CERTIFIED EXPERT
Distinguished Expert 2017

Commented:
It would be fine with me to divide the points equally amongst all.
Tony GardnerSr. Programmer/Analyst

Author

Commented:
I hope you find my point distribution amenable. I even asked my Dad for advice on this!
HainKurtSr. System Analyst
CERTIFIED EXPERT

Commented:
no rejection... whatever you decide, it is ok for me :)
Unlock the solution to this question.
Thanks for using Experts Exchange.

Please provide your email to receive a sample view!

*This site is protected by reCAPTCHA and the Google Privacy Policy and Terms of Service apply.

OR

Please enter a first name

Please enter a last name

8+ characters (letters, numbers, and a symbol)

By clicking, you agree to the Terms of Use and Privacy Policy.