How to find the TypeOf a VB6 control in VB.NET - vb.net

I am writing a .NET DLL to iterate through all controls in the a VB6 Form passed byref.
So far it seems to work VB.NET code:
Public Sub AddFormRefLegacy(ByRef strAppName As String, ByRef objForm As Object)
'update the forms caption
objForm.Caption = FindValue(strAppName, objForm.Name, "", "0", objForm.Caption)
'iterate through all the controls on the form
For Each ctl As Object In objForm.Controls
if TypeOf ctl is Label then
'this doesn't pick up any labels
end if
Next
End Sub
Called from this VB6 code:
Dim libDD As New Lib.clsDataDictionary
libDD.AddFormRefLegacy "nnne", Me
but the TypeOf operator does not work. Is there another way to find the type of control?

Could it be you're comparing two different "Label" type objects.
You haven't qualified the LABEL type in the IF TYPEOF line, so you could be comparing a VB6 label to a .net label, and they wouldn't be the same.
You could use TYPENAME, but that might not be exactly what you need iether. I'd make sure you're really comparing the types that you think you're comparing.

Have you tried using the TypeName function? Does it return anything useful for TypeName(ctl)?

Related

Create a ComboBox object to pass it into a Sub

I am trying to access a ComboBox on a UserForm from a sub. Therefore I'm trying to pass a Combobox object into it.
However, I don't seem to be able to create a Combobox Object in order to pass it in. They are always empty when entering the sub. This is what I've been trying:
Dim ctl As ComboBox
Set ctl = Me.cb_FcnName 'cb_FcnName is the name of the Combobox I'm trying to access
Call ColumnEntries2Combobox(ctl)
And this is my Sub:
Private Sub ColumnEntries2Combobox(ByRef Combo As ComboBox)
Combo.AddItem = Worksheets(WorksheetName).Cells(currRow, 2)
End Sub
For some reason I can't seem to find any documentation on how to create the necessary combobox object to pass into the sub...
Thanks in advance for any kind of help!
AddItem is a method, not a property. For a method we supply arguments after a space, compared to setting a property equal to something.
So change
Combo.AddItem = Worksheets(WorksheetName).Cells(currRow, 2)
to
Combo.AddItem Worksheets(WorksheetName).Cells(currRow, 2)
This is a common error, so a simple demonstration is:
object.Property = value
object.Method arg1, arg2

Loop - set Textboxes to ReadOnly in all Groupboxes

I have groupboxes that contain textboxes and I want to set all of them to ReadOnly=True. Here is what I tried (doesn't work):
EDIT (I forgot about Split container):
For Each SplitCon As Control In Me.Controls
If TypeOf SplitCon Is SplitContainer Then
For Each GBox As Control In SplitCon.Controls
If TypeOf GBox Is GroupBox Then
For Each ctrl As Control In GBox.Controls
If TypeOf (ctrl) Is TextBox Then
CType(ctrl, TextBox).ReadOnly = True
End If
Next
End If
Next
End If
Next
You can simplify things a great deal. Rather than looking thru all sorts of Control collections, create an array to act as a ToDo list. Then you can get rid of all the TypeOf and CType in the loop used.
' the ToDo list
Dim GrpBoxes = New GroupBox() {Groupbox1, Groupbox2,
Groupbox3, Groupbox4}
For Each grp In GrpBoxes
For Each tb As TextBox In grp.Controls.OfType(Of TextBox)()
tb.ReadOnly = True
Next
Next
Your code no longer depends on the form layout of the moment. The only thing you have to remember is to add any new GroupBox items to your list. You can also declare the array once ever for the whole form if you prefer (or even in the For Each statement)
Rather than working with Control objects, Controls.OfType(Of T) filters the collection and returns an object variable of that type, so there is no need to cast it or skip over controls you are not interested in. You can also tack on a Where method to further refine the list to include only do those with a certain name or Tag.

Convert Control Using Cast Not Working

i have a control named SuperValidator1 on every form with SuperValidator type. i want to find this control and enable it using its name because the name is consistent in all forms. so this is the code i came up with :
Dim validator As SuperValidator
Dim frm As Form = Me.ParentForm
Dim ctrl As Control()
ctrl = frm.Controls.Find("SuperValidator1", True)
Dim singleCtrl As Control = ctrl(0)
validator = TryCast(singleCtrl, SuperValidator) '< ERROR LINE
it throws editor error : Value of Type 'Control' cannot be converted to 'SuperValidator'
i tried CType and DirectCast but it is the same. according to this i should be able to cast any data type. what is wrong and what should i do ?
btw SuperValidator is from DevComponents.DotNetBar.Validator
thanks
Since SuperValidator is a component you must get it from your form's component collection. However at runtime components don't seem to inherit a name, so finding the exact one might be tricky.
As far as I know your only options are:
A) Get the first SuperValidator you can find, or
B) Match its properties (if possible).
Either way you do it you must iterate through the Me.components.Components collection:
Dim validator As SuperValidator = Nothing
For Each component In Me.components.Components
If component.GetType() Is GetType(SuperValidator) Then
validator = DirectCast(component, SuperValidator)
'Perform additional property checking here if you go with Option B.
End If
Next
Here is a test that uses a control I have on a form. Changed your logic slightly. Give it s try and see what results you have.
Dim validator As RichTextBox ' SuperValidator
Dim frm As Form = Me ' .ParentForm
Dim ctrl() As Control = frm.Controls.Find("RichTextBox1", True) ' ("SuperValidator1", True)
If ctrl.Length > 0 Then
validator = TryCast(ctrl(0), RichTextBox) ' , SuperValidator) < ERROR LINE
Else
Stop
End If

Set the order in which form controls are looped through

I'm looping through all of the controls on a certain Tab Page and the grabbing the .tag property for some further actions from checkboxes that are checked.
However, I require these controls to be looped in a certain order (I was hoping they'd be ordered by tab index), but it appears that they are not.
Is there any way to force the order that they are looped? Thanks.
Dim objCtrl As Control
For Each objCtrl In Me.objConfigForm.tabPageGeneral.Controls
If TypeOf objCtrl Is CheckBox AndAlso DirectCast(objCtrl, CheckBox).Checked Then
Dim strProp As String = DirectCast(objCtrl, CheckBox).Tag
Dim strListItem As String = CallByName(objUser, strProp, CallType.Get)
lstGeneral.Add(strListItem)
End If
Next
Use LINQ to sort the controls by TabIndex, like this:
For Each objCtrl As Control In Me.Controls.Cast(Of Control).OrderBy(Function(c) c.TabIndex)
If TypeOf objCtrl Is CheckBox AndAlso DirectCast(objCtrl, CheckBox).Checked Then
Dim strProp As String = DirectCast(objCtrl, CheckBox).Tag
Dim strListItem As String = CallByName(objUser, strProp, CallType.Get)
lstGeneral.Add(strListItem)
End If
Next
Note: The above code requires the System.Linq namespace be imported into your code file to support the Cast() and OrderBy() LINQ extension methods.
Use the .OrderBy() extension to choose an order. Also, while we're at it, you can replace the If block with Where() and OfType() extensions to reduce nesting and casting:
For Each box As CheckBox In Me.Controls.OfType(Of CheckBox)() _
.Where(Function(b) b.Checked) _
.OrderBy(Function(b) b.TabIndex)
lstGeneral.Add(CallByName(objUser, box.Tag, CallType.Get))
Next
Update: this is a bit old, but it came back into my feed today, so it's still indexed by Google somewhere. With that in mind, today I'd write the code like this instead:
Dim selectedCheckboxNames = Me.Controls.
OfType(Of CheckBox)().
Where(Function(b) b.Checked).
OrderBy(Function(b) b.TabIndex).
Select(Function(b) CallByName(objUser, b.Tag, CallType.Get))
lstGeneral.AddRange(selectedCheckboxNames)
One of the important change is introducing a variable for the result of the linq query. This can sometimes add valuable insight to code for future developers, and it always helps make the For Each loop easier to read... assuming you haven't also been able to convert to an AddRange(), as I've done here. I'm also more comfortable now taking advantage of implicit line continuations and Option Infer.

Invalid Conversion error

I recently upgraded a VB 6 project to .net. I'm having a problem with this block of code:
Dim CtrlName As System.Windows.Forms.MenuItem
For Each CtrlName In Form1.Controls
'Some code here
Next CtrlName
Now this code compiles but throws the following runtime error:
Unable to cast object of type 'System.Windows.Forms.Panel' to type 'System.Windows.Forms.MenuItem.
I have a panel control on the subject form. How do I resolve this?
Thanks.
You are iterating over all controls that are directly inside the form, not just the MenuItems. However, your variable is of type MenuItem. This is causing the problem.
For normal controls (e.g. Buttons), you’d want to use the following, easy fix; test inside the loop whether the control type is correct:
For Each control As Control In Form1.Controls
Dim btt As Button = TryCast(control, Button)
If btt IsNot Nothing Then
' Perform action
End If
Next
However, this does not work for MenuItems since these aren’t controls at all in WinForms, and they aren’t stored in the form’s Controls collection.
You need to iterate over the form’s Menu.MenuItems property instead.
The items in the Controls property of a form, which may or may not be MenuItem. Assuming that you just want to iterate over MenuItem objects you can change your code to:
For Each menuControl As MenuItem In Me.Controls.OfType(Of MenuItem)
' Some code
Next
Note that the menuControl variable is declared in the For so is only accessible within the block and is disposed automatically.
for each ctrl as control in me.controls
if typeof ctrl is menuitem then
' do stuff here
end if
next
typeof keyword allows you to test the type of control being examined in the control collection.
Found the answer after a bit of research, you need to search for the menu strip first and then loop through the items collection.
For Each ctrl As Control In Me.Controls
If TypeOf ctrl Is MenuStrip Then
Dim mnu As MenuStrip = DirectCast(ctrl, MenuStrip)
For Each x As ToolStripMenuItem In mnu.Items
Debug.Print(x.Name)
Next
End If
Next