Inserting text into a textbox at the cursor position VB - vb.net

I am trying to work out how I can insert the string "End" into my textbox at a specific cursor point?
(where the '???' is in the code below)
As you can see by the code below this will happen when the user clicks return on the keyboard within the textbox.
I have the code to get the cursor index which is being stored as integer 'intcurrentcolumn'.
Thanks
Private Sub Enter_Click(ByVal Sender As System.Object, ByVal k As System.Windows.Forms.KeyEventArgs)
Dim MyTextBox As TextBox = sender
Dim intindex As Integer
Dim intcurrentcolumn As Integer
Dim NewString As String
If k.KeyCode = Keys.Return Then
k.SuppressKeyPress = True
intindex = MyTextBox.SelectionStart
intcurrentColumn = intindex - MyTextBox.GetFirstCharIndexFromLine(intcurrentLine)
If intindex = MyTextBox.Text.Length Then
NewString = MyTextBox.Text & "<End>"
Else:
???
End If
MyTextBox.Text = NewString
'Sets cursor to end of textbox
MyTextBox.Select(MyTextBox.Text.Length, 0)
End If
Thanks In Advance !

The String.Insert method works but resets the cursor position which is generally not what you want (although your code resets it afterwards anyway). A better alternative is to just set the SelectedText:
MyTextBox.SelectedText = "<End>"
In your case, the selected text simply has length 0 before you insert the string "<End>".
This also makes the If…Else distinction unnecessary.
Private Sub Enter_Click(ByVal Sender As Object, ByVal k As System.Windows.Forms.KeyEventArgs)
If k.KeyCode = Keys.Return Then
Dim MyTextBox As TextBox = DirectCast(sender, TextBox)
MyTextBox.SelectedText = "<End>"
MyTextBox.SelectionStart = MyTextBox.Text.Length
k.SuppressKeyPress = True
End If
End Sub
Note that I’ve also fixed a bug in your code: the assignment of sender to MyTextBox needs an explicit cast! If your original code compiled, you should (!) set Option Strict On. This is essential for improved type checking by the compiler, and should be seen as an unconditional requirement1.
Furthermore, don’t declare variables before you use them. Declare them at the latest possible point, when you first assign a value to them. This makes the program state easier traceable and often results in shorter code.
1 (unless you work a lot with COM late binding, in which case you can disable it on a per-file base).

Look at the String.Insert Method, something like this
MyTextBox.Text = MyTextBox.Text.Insert(intindex, "<End>")

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

Revert the DataGridViewCell to the value before it was changed by the user

I have a DataGridView like this:
The Quantidade column can be changed by the user and the others are read only. I came up with this code that if the user changes the value of Quantidade manually on the DataGridView it checks the database to see if it has enough in stock. So if the value inputted by the user is less than the total in stock it changes normally but my question is if the user inputs a value bigger than the value in stock I want the DataGridViewCell to return to the value before it has been changed by the user.
Any ideas on how to do this?
Here is the code of the event:
Private Sub DataGridView1_CellValueChanged(sender As Object, e As DataGridViewCellEventArgs) Handles DataGridView1.CellValueChanged
'this part is to check the total of the product in the db
Dim Produtoid As String = DataGridView1.Rows(e.RowIndex).Cells(0).Value
Dim tabelaqndDisponivel As DataTable = CAD.GetData("SELECT quantidadeExistenteProduto FROM Produto where idProduto = " & Produtoid)
'qntDisponivel is a integer that holds the total quantity of the product in the db
Dim qntDisponivel As Integer = tabelaqndDisponivel.Rows(0).Item(0)
If DataGridView1.Rows(e.RowIndex).Cells(2).Value <= qntDisponivel Then
'inserts normally
Else
'now here the value on cell "quantidade" should revert
End If
End Sub
Note that This DataGridView is pretty simple. It takes the value from the ComboBox Produto and text from the TextBox Quantidade
An alternative that I often use is to save it to the .Tag, every object has a .Tag and it saves declaring a variable globally if you want to use it throughout the code.
Whilst not necessarily shorter code it does prove very useful at times and overall is tidier in my opinion as you don't have to declare a variable (you can save it to the cell or row .Tag but that is even longer code).
Usage in your application:
Private Sub dataGridView1_CellValidating(ByVal sender As Object, ByVal e As DataGridViewCellValidatingEventArgs) Handles DataGridView1.CellValidating
DataGridView1.Tag = DataGridView1.Rows(e.RowIndex).Cells(2).Value
End Sub
Retrieval:
Else
'now here the value on cell "quantidade" reverts to the value before being changed
DataGridView1.Rows(e.RowIndex).Cells(2).Value = DataGridView1.Tag
End If
My answer is to provide some help on a few issues with your code. Since we have already discussed your question at hand and a fix has been implemented I think it would be worthwhile addressing these issues.
Turn Option Strict On:
Restricts implicit data type conversions to only widening conversions, disallows late binding, and disallows implicit typing that results in an Object type.
First DataGridView1.Rows(e.RowIndex).Cells(0).Value is type Object and so to resolve this we need to append .ToString() to it like so:
Dim Produtoid As String = DataGridView1.Rows(e.RowIndex).Cells(0).Value.ToString()
Second tabelaqndDisponivel.Rows(0).Item(0) and DataGridView1.Rows(e.RowIndex).Cells(2).Value are too type Object. With these I would handle using Integer.TryParse. You can then also check the Integer values correctly:
Dim qntDisponivel As Integer = 0
Dim qnt As Integer = 0 'You can give this a more meaningful name
If Integer.TryParse(tabelaqndDisponivel.Rows(0).Item(0).ToString(), qntDisponivel) AndAlso
Integer.TryParse(DataGridView1.Rows(e.RowIndex).Cells(2).Value.ToString(), qnt) Then
If qnt <= qntDisponivel Then
'inserts normally
Else
'now here the value on cell "quantidade" reverts to the value before being changed
DataGridView1.Rows(e.RowIndex).Cells(2).Value = valorqnt
End If
Else
'Haven't been able to check so revert
DataGridView1.Rows(e.RowIndex).Cells(2).Value = valorqnt
End If
Thirdly DataGridView1.Rows(e.RowIndex).Cells(2).Value inside your CellValidating method is again type Object. Change using Integer.TryParse:
Integer.TryParse(DataGridView1.Rows(e.RowIndex).Cells(2).Value.ToString(), valorqnt)
Lastly your SQL statement is open to SQL injection. You would need to look into SQL parameters. It's quite difficult to provide much help in this area as I can't see what GetData does and it would be outside the scope of this question but it is definitely worth a mention.
So what I did here was create a variable Private valorqnt As Integer and on the event CellValidating I saved the value (before being changed by the user) into it.
Code:
Private Sub dataGridView1_CellValidating(ByVal sender As Object, ByVal e As DataGridViewCellValidatingEventArgs) Handles DataGridView1.CellValidating
valorqnt = DataGridView1.Rows(e.RowIndex).Cells(2).Value
End Sub
This way I have the value of the cell before being changed. Now on the CellValueChanged event I added DataGridView1.Rows(e.RowIndex).Cells(2).Value = valorqnt so I could revert the value.
Code:
Private Sub DataGridView1_CellValueChanged(sender As Object, e As DataGridViewCellEventArgs) Handles DataGridView1.CellValueChanged
'this part is to check the total of the product in the db
Dim Produtoid As String = DataGridView1.Rows(e.RowIndex).Cells(0).Value
Dim tabelaqndDisponivel As DataTable = CAD.GetData("SELECT quantidadeExistenteProduto FROM Produto where idProduto = " & Produtoid)
'qntDisponivel is a integer that holds the total quantity of the product in the db
Dim qntDisponivel As Integer = tabelaqndDisponivel.Rows(0).Item(0)
If DataGridView1.Rows(e.RowIndex).Cells(2).Value <= qntDisponivel Then
'inserts normally
Else
'now here the value on cell "quantidade" reverts to the value before being changed
DataGridView1.Rows(e.RowIndex).Cells(2).Value = valorqnt
End If
End Sub

Alternative Process

I have 2 buttons and a DataGridView with 2 Columns (0 & 1).
The 1st button transfers a randomized cell from the Column(1) to a TextBox. Then, it stores that Cell in variable (a), plus the cell that opposites it in variable (b).
Private Sub Button3_Click(sender As Object, e As EventArgs) Handles Button3.Click
Dim rnd As New Random
Dim x As Integer = rnd.Next(0, Form1.DataGridView1.Rows.Count)
Dim y As Integer = 1
Dim a As String = Form1.DataGridView1.Rows(x).Cells(y).Value
Dim b As String = Form1.DataGridView1.Rows(x).Cells(y - 1).Value
TextBox3.Text = a
End Sub
The 2nd button, however, is supposed to compare if another TextBox's text has the same string variable (b) has as Strings. Now, if so, then it has to display a certain message and so on...
Private Sub Button2_Click(sender As Object, e As EventArgs) Handles Button2.Click
If TextBox4.Text = b Then '<<< ISSUE HERE!
MsgBox("Correct! ^_^")
ElseIf TextBox4.Text = "" Then
MsgBox("You have to enter something first! O_o")
Else
MsgBox("Wrong! >,<")
End If
End Sub
The problem is that the variable (b) is surely not shared across the two "private" subs. And so, there is NOTHING to compare to in the 2nd button's sub! I presume that the solution here is to split the "randomization process" into a separate function, then execute it directly when the 1st button gets activated. Furthermore, that function's variables have to be SHARED somehow, and I certainly don't know how!
Thanks for Mr. Olivier, the code has been improved significantly! Yet, I still encounter a "wrong" comparison issue, somehow!
Dim RND As New Random
Dim x As Integer
Private Function GetCell(ByVal rowIndex As Integer, ByVal cellIndex As Integer) As String
Return Form1.DataGridView1.Rows(rowIndex).Cells(cellIndex).Value
End Function
Private Sub btnRoll_Click(sender As Object, e As EventArgs) Handles btnRoll.Click
x = RND.Next(0, Form1.DataGridView1.Rows.Count)
tbxRoll.Text = GetCell(x, 1)
End Sub
Private Sub btnSubmit_Click(sender As Object, e As EventArgs) Handles btnSubmit.Click
If tbxSubmit.Text = GetCell(x, 0) Then
MsgBox("Correct! ^_^")
ElseIf tbxSubmit.Text = "" Then
MsgBox("You have to enter something first! O_o")
Else
MsgBox("Wrong! >,<")
End If
End Sub</code>
Well, unbelievably, I read a guide about "comparison operations" in VB.net and tried out the first yet the most primal method to compare equality - which was to use .Equals() command - and worked like a charm! Thank God, everything works just fine now. ^_^
If tbxSubmit.Text.Equals(GetCell(x, 0)) Then
Alright now... This is going to sound weird! But, following Mr. Olivier's advise to investigate "debug" the code, I rapped the string I'm trying to compare with brackets and realized that it's been outputted after a break-line space! So, I used the following function to remove the "white-space" from both of the comparison strings! And it bloody worked! This time for sure, though. ^_^
Function RemoveWhitespace(fullString As String) As String
Return New String(fullString.Where(Function(x) Not Char.IsWhiteSpace(x)).ToArray())
End Function
If RemoveWhitespace(tbxSubmit.Text) = RemoveWhitespace(GetCell(x, 0)) Then
Turn the local variables into class fields.
Dim rnd As New Random
Dim x As Integer
Dim y As Integer
Dim a As String
Dim b As String
Private Sub Button3_Click(sender As Object, e As EventArgs) Handles Button3.Click
x = rnd.Next(0, Form1.DataGridView1.Rows.Count)
y = 1
a = Form1.DataGridView1.Rows(x).Cells(y).Value
b = Form1.DataGridView1.Rows(x).Cells(y - 1).Value
TextBox3.Text = a
End Sub
These fields can now be accessed from every Sub, Function and Property.
Of course Button3_Click must be called before Button2_Click because the fields are initialized in the first method. If this is not the case then you should consider another approach.
Create a function for the Cell access
Private Function GetCell(ByVal rowIndex As Integer, ByVal cellIndex As Integer) _
As String
Return Form1.DataGridView1.Rows(rowIndex).Cells(cellIndex).Value
End Function
And then compare
If TextBox4.Text = GetCell(x, y - 1) Then
...
And don't store the values in a and b anymore. If y is always 1 then use the numbers directly.
If TextBox4.Text = GetCell(x, 0) Then
...
One more thing: give speaking names to your buttons in the properties grid before creating the Click event handlers (like e.g. btnRandomize). Then you will get speaking names for those routines as well (e.g. btnRandomize_Click).
See:
- VB.NET Class Examples
- Visual Basic .NET/Classes: Fields

Vb.net dims in buttons turning to 0

I have this snippet from my code
Private Sub BtnOne_Click(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles BtnOne.Click
Dim ownerNum As Integer 'sets variable
ownerNum = Ownerfnc(Indicatorbtn, ownerNum) 'gives variable a number
End Sub
Function cntOwner(ByRef indicator As Object, ByRef old As Integer) As Integer
If indicator.FillColor = Color.Transparent Then
indicator.FillColor = Color.green
Return player
Else
Return old
End If
End Function
when i click the button it sets the variable to the correct number but if i click it again it sets it back to 0 is there a way to stop it from doing it?
Thanks
Declare your variable globally (outside procedure) to persist it's value.
At the moment, your variable declared locally within procedure. That way it will be recreated -hence get reset to default value- every time the procedure called. For reference, read this : MSDN - Scope in Visual Basic.
Thanks for the answers, needed to explain a bit more that i have 42 different variables that where in 42 different button clicks.
The answer was to just put static instead of dim and that worked fine for anyone that was looking for a solution like this
you should declare your variable outside the events of button click. every time you you click the button the value of ownerNum is reseting. try dis code
Dim ownerNum As Integer 'sets variable
Private Sub BtnOne_Click(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles BtnOne.Click
'now every time you click the ownerNum is not reseting.
ownerNum = Ownerfnc(Indicatorbtn, ownerNum) 'gives variable a number
End Sub
Function cntOwner(ByRef indicator As Object, ByRef old As Integer) As Integer
If indicator.FillColor = Color.Transparent Then
indicator.FillColor = Color.green
Return player
Else
Return old
End If
End Function

Autocomplete for single word in datagridview

I would need to implement a autocomplete feature in a datagridview cell. I would need it to work on a word by word basis, like it is in the SMS app on android. After I type a whitespace it should start looking for the word I am typing and propose it based on the other words i have already used inside the same Datagridview.
Its more a word suggestion, that if i hit tab autocompletes that word for me.
Is this possible? I know how to do it based on the entire cell, but have no clue on how to do it based on the single word. (like Google)
Thanks
EDIT:
So far I have this. The concept is working, but I need to update the list each time that a key is pressed. Any help on this?
Private Sub DataGridView2_EditingControlShowing(sender As Object, e As DataGridViewEditingControlShowingEventArgs) Handles DataGridView2.EditingControlShowing
wrdlst.Add("arabia")
wrdlst.Add("burundi")
wrdlst.Add("closed")
wrdlst.Add("afganistan")
wrdlst.Add("door")
wrdlst.Add("banana")
wrdlst.Add("apple")
Dim basestring As String = Nothing
basestring = CStr(DataGridView2.CurrentCell.Value)
If Not IsNothing(basestring) Then
Dim lastword As String
Dim lastspaceindex As Integer = basestring.LastIndexOf(" ") + 1 '''+1 to get index after whitespace and compensate for -1 result
lastword = basestring.Substring(lastspaceindex)
Dim ItemCode As TextBox = TryCast(e.Control, TextBox)
If ItemCode IsNot Nothing Then
ItemCode.AutoCompleteMode = AutoCompleteMode.SuggestAppend
'ItemCode.AutoCompleteCustomSource = wrdlst
For Each element As String In wrdlst
If element.StartsWith(lastword) Then
ItemCode.AutoCompleteCustomSource.Add(basestring.Substring(0, lastspaceindex) & element)
End If
Next
ItemCode.AutoCompleteSource = AutoCompleteSource.CustomSource
End If
End If
End Sub
Private Sub DataGridView2_KeyUp(sender As Object, e As KeyEventArgs) Handles DataGridView2.KeyUp
??????????????????????????????????????????
End Sub