How To Evaluate a String Containing References to Windows Forms Controls At Runtime? - vb.net

How can you, in VB.Net, evaluate the value of controls referenced in a string? Suppose you have a textbox N containing some alphanumeric content and it were referenced in a string variable like this:
Dim s As String = """Hello "" & N.Text & ""!"""
I'd like to be able to reevaluate the contents of the s variable elsewhere in the code (where there's no direct knowledge of the existence of N), for example, like this:
Dim e As String = Eval(s)
This isn't possible with VB.Net; no such Eval function is available. I've seen some nearly plausible solutions online such as using the old COM ScriptControl:
Private Shared _scriptControl As MSScriptControl.ScriptControl = New ScriptControl()
_scriptControl.Language = "VBScript"
Dim e As String = _scriptControl.Eval(s)
However, the reference to the N.Text property of a Windows Forms control is alien to the ScriptControl object, and therefore it throws an error.
Is there any other quick fix that won't require the purchase of a third-party component?

However, the reference to the N.Text property of a Windows Forms
control is alien to the ScriptControl object, and therefore it throws
an error. ... I only mentioned the ScriptControl idea to fend off
answers that might involve that approach I mentioned since I already
tried it and don't want to waste our time.
You can add the TextBox to the Script Control. First, get a reference to "N" using it's Name. Not sure if you've got the name of the control by itself already; if not, you may need to parse your string to get the name. Then use Controls.Find() to get a reference and pass that to AddObject(). Now your string can be evaluated as expected:
Private Shared _scriptControl As MSScriptControl.ScriptControl = New ScriptControl()
Private Sub Form1_Load(sender As Object, e As EventArgs) Handles MyBase.Load
_scriptControl.Language = "VBScript"
End Sub
Private Sub Button1_Click(sender As Object, e As EventArgs) Handles Button1.Click
Dim ctlName As String = "N"
Dim ctl As Control = Me.Controls.Find(ctlName, True).FirstOrDefault
If Not IsNothing(ctl) Then
Try
_scriptControl.AddObject(ctlName, ctl)
Catch ex As Exception
End Try
Dim code As String = """Hello "" & N.Text & ""!"""
Dim result As String = _scriptControl.Eval(code)
MessageBox.Show(result)
End If
End Sub

String Interpolation was introduced in Visual Basic 14. Since the control is declared as a Friend variable in the Form's designer, then presumably you could use the reference to the control in the String like this:
Dim s As String = $"Hello {N.Text}!"

Related

How can I use a variable to reference a textbox?

I'm new to visual basic and programming in general, but I'm trying to make a statistic counter sort of program. I'm trying to use a variable to reference a textbox, for example, k_kills(i) = txtKills(i).Text. This doesn't work, however, so I then tried the following:
For i = 0 To 8
Dim tempBox As TextBox
Dim tempName As String = "txtKills" & i.ToString
tempBox = Me.Controls.Item(tempName)
k_kills(i) = tempBox.Text
Next
This also doesn't work and spits out an error each time saying that 'tempBox was Nothing'.
Can anyone tell me if I can make this work?
Thanks.
You will need to find the control in some collection. By default the control would exist in its parent's Controls property and since you're trying to get the control by its name then you could use ControlCollection's Find method. If you can guarantee that the control's parent is the Form then you'd call:
Dim tempBox As TextBox = DirectCast(Me.Controls.Find(tempName, False), TextBox)
But if there is the possibility that the control's parent is something other than the Form then you'd call:
Dim tempBox As TextBox = DirectCast(Me.Controls.Find(tempName, True), TextBox)
The first would execute slightly quicker because it only iterates over the current ControlCollection whereas the second could take longer because if it cannot find the control in the current ControlCollection then it starts to iterate over the child controls as well.
Assuming the controls are all in Form as parent and they all start with txtKills...
If you are going to use these text boxes as a group for several actions you may want to build an array or list of TextBox.
Dim Kills(7) As TextBox
Private Sub CreateTextBoxArray()
Dim index As Integer
For Each ctrl As Control In Controls
If ctrl.Name.StartsWith("txtKills") Then
Kills(index) = DirectCast(ctrl, TextBox)
index += 1
End If
Next
End Sub
Private Sub ClearKillTextBoxes()
For Each t In Kills
t.Clear()
Next
End Sub
Private Function GetTextFromKillBoxes() As List(Of String)
Dim lst As New List(Of String)
For Each t In Kills
lst.Add(t.Text)
Next
Return lst
End Function
After Mary's comment I edit my answer to add this line --> My code does not work if Option Strict is On and 'For' starting in 0 or 1 or any number and txtKills[X] exists.
This was my previous answer and I don't know if I have to delete or not:
Your code works fine but I think you have an error because your For starts in 0 and you don't have any "txtKills0". I've tested it now:
Private Sub Button1_Click(sender As Object, e As EventArgs) Handles Button1.Click
Dim k_kills(10) As String '<< Ignore the length
For i = 1 To 7
Dim tempBox As TextBox
Dim tempName As String = "txtKills" & i.ToString
tempBox = Me.Controls.Item(tempName)
k_kills(i) = tempBox.Text
MsgBox(k_kills(i))
Next
End Sub

Find and Replace using another form

I have my frmMainwhich has RichTextBox1 and I have a button btnfind&Replacewhich whose click event pops out another minute form frmFindandReplace which has two textboxes: TextBoxSearch and TextBoxReplace with two buttons: replaceButton and findButton. I cannot seem to get my code for instances of finding a word in textbox and an instance of replacing it. Here is my code:
Public Class frmFindandReplace
Dim txtClientArea As RichTextBox
Private Sub TextBoxSearch_TextChanged(sender As Object, e As EventArgs) Handles TextBoxSearch.TextChanged
End Sub
Private Sub frmFindandReplace_Load(sender As Object, e As EventArgs) Handles MyBase.Load
End Sub
Private Sub replaceButton_Click(sender As Object, e As EventArgs) Handles replaceButton.Click
End Sub
Protected Friend Sub findButton_Click(sender As Object, e As EventArgs) Handles findButton.Click
Dim a As String
Dim b As String
a = TextBoxSearch.Text
b = InStr(StartPosition, a, txtClientArea)
If b Then txtClientArea.Focus()
txtClientArea.SelectionStart = b - 1
txtClientArea.SelectionLength = Len(a)
txtClientArea.ScrollToCaret()
End Sub
The findButton code doesnot even work. Throws an error!
Error 3: Overload resolution failed because no accessible 'InStr' can be called with these arguments:
'Public Function InStr(Start As Integer, String1 As String, String2 As String, [Compare As Microsoft.VisualBasic.CompareMethod = Microsoft.VisualBasic.CompareMethod.Binary]) As Integer': Value of type 'System.Windows.Forms.TextBox' cannot be converted to 'String'.
'Public Function InStr(String1 As String, String2 As String, [Compare As Microsoft.VisualBasic.CompareMethod = Microsoft.VisualBasic.CompareMethod.Binary]) As Integer': Value of type 'System.Windows.Forms.RichTextBox' cannot be converted to 'Microsoft.VisualBasic.CompareMethod'. C:\Users\Joseph GodwinKE\Documents\Visual Studio 2013\Projects\simpleapp\frmFindandReplace.VB 25 13 Simple app
I know I have not done much but am new and all my efforts of searching a solution over the internet have failed! Thank you I hope someone will help me pls.
A few pointers:
InStr returns an integer.
Check the documentation as it'll show you have the search values the wrong way around.
Turn Option Explicit on to help find your issues.
This should work better.
Private Sub findButton_Click(sender As Object, e As EventArgs) Handles findButton.Click
Dim searchString As String
Dim findPos As Integer
Try
searchString = TextBoxSearch.Text
findPos = InStr(txtClientArea.Text, searchString)
If findPos > 0 Then txtClientArea.Focus()
txtClientArea.SelectionStart = findPos - 1
txtClientArea.SelectionLength = searchString.Length
txtClientArea.ScrollToCaret()
Catch ex As Exception
MessageBox.Show(String.Concat("An error occurred: ", ex.Message))
End Try
End Sub
If you want your code work you need to pass the reference to the RichTextBox present in the first form to the findandReplace form.
Otherwise you will not be able to work with that instance of the RichTextBox.
Usually, this means that when you create and open an instance of the findandReplace form you pass the reference to the RichTextBox to work with in the call to the constructor. Something like this
Dim fReplace As frmFindandReplace = New frmFindandReplace(Me.txtClientArea)
fReplace.Show()
Here the New call reaches the constructor of frmfindandReplace. This call is usually hidden by VB.NET but you could add it writing explicit code for it
Public Class frmFindandReplace
Dim txtClientArea As RichTextBox
Public Sub New (ByVal txt as RichTextBox)
txtClientArea = txt
End Sub
Now the global variable txtClientArea inside the findandReplace class is assigned to the existing reference of the RichTextBox present in the first form and you could happily work with it
Protected Friend Sub findButton_Click(sender As Object, e As EventArgs) Handles findButton.Click
Dim a As String
a = TextBoxSearch.Text
Dim position = txtClientArea.Find(a, 0, RichTextBoxFinds.MatchCase)
.....
End Sub
And please make yourself a favor and start using the more complete methods available from the NET Framework library and stop using the old fashioned VBA methods.
For example the RichTextBox has a method that does exactly what you are trying to do in code. Find, search the content of the textbox and if it founds a match it highlight the text and return the starting position of the text.
There is no replace builtin method but having the position and the length is really simple to implement your own replacing code.
You Have defined b as a string. Change it to an integer. Also Instr doesn't allow you to set a start position, just a string to search and the string to search for and optionally the type of search - Binary or Text.
Finally rather than type If b then, use If b>0 then rather than turning off Option Strict. It's always better to write code with Option Strict on as it makes you write better code and in the long run is easier to chase down errors

Vb.Net Control Variable Names

I am trying to create bunch of WebBrowsers with Variable Names; I started with the following code, but seems it has something wrong that I cannot figure our;
The error is in the FIRST PORTION OF THE CODE;
Any help/comment appreciated:
Public Class Form1
Private Sub Button1_Click(sender As Object, e As EventArgs) Handles Button1.Click
Dim NumberOfBrowsers As Integer = 12
For Pro As Integer = 1 To NumberOfBrowsers
Dim frmNew As New Form
'------------------------- FIRST PORTION:
Dim MekdamBrowser As New WebBrowser
MekdamBrowser = "WebBrowser" & Pro
frmNew.Controls.Add(MekdamBrowser)
'-------------------------
MekdamBrowser.Location = New System.Drawing.Point(10, 10)
MekdamBrowser.Size = New System.Drawing.Size(300, 300)
MekdamBrowser.Show()
'-------------------------
Next
End Sub
End Class
Thanks
It seems that you want the first portion to be as follow instead :
'------------------------- FIRST PORTION:
Dim MekdamBrowser As New WebBrowser
MekdamBrowser.Name = "WebBrowser" & Pro
frmNew.Controls.Add(MekdamBrowser)
'-------------------------
The difference between this and the original code you tried is, above code assigns name for WebBrowser control, where corresponding line of code in question tried to "replace" WebBrowser control it self with a name (it tried to assign string data to variable of type WebBrowser which is not a valid operation).

Using a combo box to store items in an array from a text file and then using that array and its components in another form

I'm currently designing an application within visual basic using vb.net. The first form asks for login information and then prompts the next form to select a customer. The customer information is stored in a text file that gets put in an array. I next have a form for the user to display and edit that information. How can I use the array I already created in the previous form in my display and edit form?
Private Sub frmCustomerList_Load(sender As Object, e As EventArgs) Handles MyBase.Load
Dim sr As StreamReader = File.OpenText("customer.txt")
Dim strLine As String
Dim customerInfo() As String
Do While sr.Peek <> -1
strLine = sr.ReadLine
customerInfo = strLine.Split("|")
cboCustomers.Items.Add(customerInfo(0))
customerList(count) = strLine
count = count + 1
Loop
End Sub
Private Sub cboCustomers_SelectedIndexChanged(sender As Object, e As EventArgs) Handles cboCustomers.SelectedIndexChanged
Dim customerInfo() As String
Dim index As Integer = cboCustomers.SelectedIndex
Dim selectedCustomer As String = customerList(index)
customerInfo = selectedCustomer.Split("|")
End Sub
Make the next form require it in the constructor:
Public Class EditCustomer
Public Sub New(customerInfo As String())
InitializeComponent() 'This call is required, do not remove
'Yay! Now you have your info
End Sub
End Class
You'd call it by doing something like...
Dim editForm = New EditCustomerFrom(customerInfo)
editForm.Show()
Alternatively, you could have a property on the form you set.
Dim editForm = New EditCustomerFrom()
editForm.Customer = customerInfo
editForm.Show()
Then inside the Load event of that form, you'd write the logic that would display it looking at that property.
Aside: You should look at maybe defining an object to hold customer info and do some JSON or XML serialization for reading/writing to the file, IMO. This architecture is kind of not good as is....

Using password character "*" in InputBox

I want to use * character in inputbox but an error prompts
conversion from "*" to string invalid
How can I make my inputbox hide typed text into password characters?
Here is my code
Dim value As String
value = InputBox("Security Check", " Enter password", "*")
If value = "123456" Then
numr.Enabled = True
End If
End Sub
This is not possible with the built in Function InputBox. Ths value you are setting "*" is the defaultvalue of that function. http://msdn.microsoft.com/en-us/library/6z0ak68w(v=vs.90).aspx
Here is something you could do. http://www.vbforums.com/showthread.php?627996-Accepting-password-characters-for-InputBox-function
You have to define it yourself this is the Code I wrote to make a custom Password Input Box I defined it as a class and then inherited the form class and gave it custom properties By doing this I have created a property that determines if access is granted or not. you can create encryption and communicate with Database for password retrieval but this simply shows how to use the custom control.
Public Class Form1
Dim test As New CustomForm("workflow")
Public Class CustomForm
Inherits Form
Property SecretPassword As String
Property GrantAccess As Boolean
Sub New(Password As String)
GrantAccess = False
Me.SecretPassword = Password
Dim lbl As New Label
lbl.Text = "Password"
Me.Controls.Add(lbl)
Me.Text = "***PASSWORD INPUT REQUIRED***"
Dim frmSZ As New Size(400, 100)
Me.Size = frmSZ
Dim IBox As New TextBox
AddHandler IBox.KeyDown, AddressOf TextBox1_KeyDown
Dim ibox20 As New Point(100, 0)
IBox.Location = ibox20
IBox.PasswordChar = "*"
Me.Controls.Add(IBox)
Me.Show()
End Sub
Private Sub TextBox1_KeyDown(sender As Object, e As KeyEventArgs)
If e.KeyCode = Keys.KeyCode.Enter Then
Try
Dim passswordInput As String = sender.text
If passswordInput = Me.SecretPassword Then
GrantAccess = True
Me.Dispose()
Else
MsgBox("Sorry the password you entered is not correct please try again. The password is case sensitive make sure your caps lock is not on.")
End If
Catch ex As Exception
End Try
End If
End Sub
End Class
Private Sub Button1_Click(sender As Object, e As EventArgs) Handles Button1.Click
MsgBox(test.GrantAccess)
End Sub
End Class
Unfortunately, the InputBox function doesn't have this parameter. VB.Net is reading your "*" as the value for the DefaultResponse parameter, or what value will equal if the user just accepts the default entry.
As a matter of fact, InputBox, while still found in the VisualBasic Namespace, is not considered up to date coding practice since 2003, but is still used by many who are or were accustomed to VB6 (including myself). It's most recent entry in the MSDN Visual Basic Reference is for the 2008 version of Visual Studio, and is not found in the current (2017) Visual Basic Language Reference.
The standard way of using an * or other password character in .Net, is to use a Windows Forms TextBox, and then use either the PasswordChar or UseSystemPasswordChar properties to change the nature of the TextBox inside the Form. These can be accessed in the in the Form Design Properties window, or as properties of the TextBox within your code.