Make ListView FindItemWithText match entire text - vb.net

I have a ListView with two columns, and before enter a new item in the listview, I want to prevent entering a duplicate value, so I found ListView.FindItemWithText to accomplish that.
But I realized that if I enter 232323, and then enter 2323, which is different but starts with the same digits as the first entry, the function returns that item as a match.
I wonder if there is any way to match the whole text (exact text) to avoid the above.
Here is my code:
Dim ChkSIM As New ListViewItem
ChkSIM = lvItems.FindItemWithText("2323")
If Not ChkSIM Is Nothing Then
lblErrorSIM.Text = "Already in list"
End If

ListView.FindItemWithText has an overload to find only exact matches:
Dim ChkSIM As ListViewItem = lvItems.FindItemWithText("2323", True, 0, False)
For more information, see the documentation.

Related

How to search only the first line of a multiline textbox in VB.NET

Is there any way to search only the first line of a Multiline Textbox without knowing exactly at what position the text is you're looking for?
If I knew the position of the text I was looking for I could do something like:
Dim myNotes As String = "The book has a lot of text"
Dim myText As String = "text"
If Not myNotes.Substring(0,4) = myText Then
' Do Something
End If
Or if I wanted to search the entire textbox I could do something like:
Dim myNotes As String = "The book has a lot of text"
Dim myText As String = "text"
If Not myNotes.Contains(myText) Then
' Do Something
End If
But I want to search only the first line of the textbox and I'm not sure at what position the text may be. Is there anyway to do a search like that?
This is another example of why you should ALWAYS read the relevant documentation. If you had read the documentation for the TextBox class then you'd know that it has a Lines property. To get the first line of text, you simply get the first element of that array:
Dim firstLine = myTextBox.Lines(0)
If Not filrstLine.Contains(myText) Then
'Do something
End If
Note that this only applies where the user has explicitly added a line break to the text. I assume that that is what you want, given that you have accepted another answer that does the same thing. If you mean the first line based on automatic word-wrap then that requires a bit more effort.
You could take the text and extract the first line.
int pos = text.IndexOfAny('\r', '\n');
if (pos >= 0)
text = text.SubString(0, pos);
// text now contains only the first line
Then you can search the resulting string.

How to insert text into a richtext textbox using VBA code

In MS Access VBA, I have been trying to programmatically insert code into a form's richtext textbox control when the user presses a button. The idea is to put a mark where the user's cursor is at the time the user presses the button--the mark will signify the start of text where the user enters a comment about the text.
However, presumably because the richtext textbox has hidden formatting codes embedded (e.g., <div>, etc.), using .SelStart and .SelLength does not seem to get me to the correct position in the textbox when I am trying to insert the new text. It is consistently inserting the text earlier in the textbox than where the cursor was when the button is clicked, but not a consistent number of characters earlier.
Although I've done a search and found some wonderful functions for inserting text into a standard textbox (e.g., Lebans' InsertAtCursor function), I cannot get those functions to work for richtext textboxes either--that is, they have the same problem as code that I wrote myself; it inserts the new text too early in the existing textbox text.
Anyone have a solution for programmatically inserting new text into a richtext textbox at the cursor position?
Here is code (obviously, I could make the code more efficient, but I was just trying to get something working first) from one of my attempts. It inserts text, but, not at the correct location, presumably due to the richtext formatting that does not visibly appear in the textbox but apparently influences .SelStart position values:
Dim intSelStart As Integer 'this is the starting location of the selection in the note at the time the comment was initially added
Dim strAddComment as String 'this is the string comment that I want to add--it is not the comment itself, it is a flag that will indicate the comment number
strAddComment = "|1`17|" 'the | characters delimit the comment flag; the first number is the comment number so 1 is the first comment, 2 is the second, etc.; the value after the ` is the length of the text selected in the textbox to which the comment applies, e.g., `17 means the comment applies to 17 selected characters
Forms!frmAppt_individual.SetFocus 'set the focus to the main form
Forms!frmAppt_individual.sub_C.SetFocus 'set the focus to the subform so we can get the .Sel property values of the text selected in the textbox on the subform
Forms!frmAppt_individual.sub_C.Form.Controls("Note").SetFocus 'set focus on the control which is required to get the .Sel property values
intSelStart = Forms!frmAppt_individual.sub_C.Form.Controls("Note").SelStart
'now try to insert the comment
Forms!frmAppt_individual.sub_C.Form.Controls("Note") = Left(Forms!frmAppt_individual.sub_C.Form.Controls("Note"), intSelStart) & strAddComment & Mid(Forms!frmAppt_individual.sub_C.Form.Controls("Note"), intSelStart + 1)
So, I am posting code below that worked for me to insert text at the current insertion point into a richtext textbox using VBA code. The use of the PlainText function seemed helpful. Hopefully the code below will help someone else trying to do the same thing.
An explanation of the code:
The function fAddComment is contained in a standard module. fAddComment is called when the user clicks a button btnAddComment on the parent form frmAppt. A subform subNoteForm contains the richtext textbox named tbxNote. The user is expected to have the insertion point at the position in the richtext textbox where the comment reference is inserted; the user may also have a number of characters selected that indicate the range of text to which the comment reference applies. The function fAddComment will determine what comment number the new comment reference will be by counting any existing comment references already in the note. The function will also count the number of characters selected when the comment reference is inserted so that a different function can later locate the comment reference and select the relevant characters. The function adds, at the insertion point, a comment emoji (💬), followed by the comment reference number, followed by a ` character, followed by the number of characters selected when the comment reference was added, ending with a terminating comment emoji. The function returns the string of the comment reference block that was added.
Public Function fAddComment() As String
'this is used to add a new comment reference to the currently showing note
'it returns "" if there is no note
'it returns the string of the comment reference added to the note if a comment reference is successfully added
Dim strBubble As String 'the comment bubble emoji string
strBubble = ChrW(55357) & ChrW(56492) 'the comment bubble emoji
Dim strProgNote As String
Dim intMaxComment As Integer 'this is the maximum comment number found
Dim intSelStart As Integer 'this is the starting location of the selection in the note at the time the comment was initially added
Dim intSelLength As Integer 'this is the selection length in the note at the time the comment was initially added
Dim whr As Integer 'this locates the next comment emoji and the emoji after it
Dim intFoundValue As Integer 'this is the value of the found comment number
Dim strNew As String 'the new string that holds the comment number and length
Dim strSelectedText As String 'the text that is selected
Dim intPosBeforeInsert As Integer 'the position of the insertion point prior to inserting the new comment reference
'first, get the text of the progress note
strProgNote = PlainText(Forms!frmAppt.subNoteForm.Form.Controls("tbxNote"))
If Len(strProgNote) = 0 Then 'there's no note, so don't try to find comments
fAddComment = ""
Exit Function
End If
'get the selection length at the time the comment was initially added
Forms!frmAppt.SetFocus 'set the focus to the main form
Forms!frmAppt.subNoteForm.SetFocus 'set the focus to the subform so we can get the length of the text selected in the textbox on the subform
Forms!frmAppt.subNoteForm.Form.Controls("tbxNote").SetFocus 'set focus on the control which is required to get the SelLength property
intSelStart = Forms!frmAppt.subNoteForm.Form.Controls("tbxNote").SelStart
intSelLength = Forms!frmAppt.subNoteForm.Form.Controls("tbxNote").SelLength
strSelectedText = PlainText(Forms!frmAppt.subNoteForm.Form.Controls("tbxNote").SelText)
'now, find each comment emoji string and get the value
intMaxComment = 0 'default to no comments
whr = 1
Do Until whr = 0
whr = InStr(whr, strProgNote, strBubble)
If whr > 0 Then 'found a comment, check the number
intFoundValue = Val(Mid(strProgNote, whr + 2)) 'the comment emoji consists of 2 characters, not just 1 character
If intFoundValue > intMaxComment Then intMaxComment = intFoundValue 'the new value is greater so make it the highest value now
whr = InStr(whr + 2, strProgNote, strBubble) + 2
End If
Loop
'return the next comment number and the length of the selected string in the note
strNew = strBubble & Trim(str(intMaxComment + 1)) & "`" & Trim(str(intSelLength)) & strBubble
'insert the new comment reference into the note
intPosBeforeInsert = Forms!frmAppt.subNoteForm.Form.Controls("tbxNote").SelStart
Forms!frmAppt.subNoteForm.Form.Controls("tbxNote").SelLength = 0 'collapse selection
Forms!frmAppt.subNoteForm.Form.Controls("tbxNote").SelText = strNew 'insert the new comment text
'move the insertion point back to the original location and after the comment reference we just added
Forms!frmAppt.subNoteForm.Form.Controls("tbxNote").SelStart = intPosBeforeInsert + Len(strNew)
fAddComment = strNew 'return the comment string we just added to the note
End Function

How to make a textbox receive changes from comboboxes and another textbox?

Essentially I am taking the inputs from these ComboBoxes shown below:
Along with the changes from this textbox:
And place both of these changes towards another, sole textbox. For instance, if I have my file name format adjusted the following way from the first screenshot, and I type in my client/company name as "apples", the textbox for "File Name" should output to this:
I want the user to type in their preferred "client name" and make my program add those changes automatically, without compromising the values/inputs from the ComboBoxes and "Client Name". I tried to look online for something like this, but the solutions provided made very little sense, or were just too confusing for me to understand. Any help will be greatly appreciated!
This is fairly broad; there are many ways it could be solved but I think I'd make it fairly simple:
I'd have the comboboxes in a list in left to right order:
Dim combos = { combobox1, combobox2, combobox3, combobox4, combobox5, combobox6 }
I'd have the replacements in a dictionary in any order, so this Dictionary is essentially a list of KeyValuePairs, the Key is what we find, and the Value is what we replace it with:
Dim repl = New Dictionary(Of String, String) From _
{ _
{"Client Name", _companyClientName.Text}, _
{"Month", DateTime.Now.ToString("MMM")}, _
{"Year", DateTime.Now.ToString("yyyy")}, _
{"Please Select", ""} _
}
And perform a set of replacements in a loop:
filenameTextBox.Clear()
For Each c as ComboBox in combos
'to track if we perform any replacement
Dim changed = False
'for each r in the list of replacements
For Each r as KeyValuePair(Of String, String) in repl
'if the text in the combo is something we replace
If c.Text = r.Key Then
'append a replacement-performed version
fileNameTextBox.AppendText(c.Text.Replace(r.Key, r.Value))
changed = True 'track that we made a change
Exit For 'don't make any more replacements
End If
End For
'if we didn't change anything, just put the text of the combo in literally
If Not changed Then fileNameTextBox.AppendText(c.Text)
End For
All this code would go in a method and then event handlers for "combo selected item changed" and/or "company name text box text chnaged" would call the method

For a combobox, selectedIndex returns 0 while selectedtext returns a value

Once I select a value from a Combobox and save the form, ComboBox.SelectedText contains the value selected but ComboBox.SelectedIndex is returning 0 always for each item in the list. Below is just a sample code for reference.
If (combobox1.SelectedIndex = 0 Or combobox1.SelectedText = "")
MessageBox.Show("No value selected")
else
MessageBox.Show("Some value selected")
End If
Some code to illustrate usage
Private Sub ComboBox1_SelectedIndexChanged(sender As Object,
e As EventArgs) Handles ComboBox1.SelectedIndexChanged
'check for no item selected
If ComboBox1.SelectedIndex < 0 Then
Stop 'no item
Else
Dim idx As Integer = ComboBox1.SelectedIndex
Dim val As String = CStr(ComboBox1.SelectedItem) '<-- use SelectedItem
Stop
End If
End Sub
Small Answer
SelectedText is not the same as SelectedItem. Take a look at ComboBox.SelectedText:
Gets or sets the text that is selected in the editable portion of a ComboBox.
I think that you are confusing this with ComboBox.SelectedItem
SelectedIndex: -1 if nothing selected, otherwise the index of the selected item
SelectedValue: null if nothing selected, otherwise the selected item
SelectedText: the text that the operator marked in the editable part of the combo box.
** Room for improvement **
You use VB. My VB is a bit rusty, so I'll give my answer in C#. I guess you'll get the gist.
In Winforms, whenever you want to fill a that shows a sequence of items, like ComboBoxes, ListBoxes, DataGridViews, Charts, etc, there are usually two methods:
Fill the ComboBox one by one with the texts that you want to display
Use a DataSource: fill it with the Items that you want to be selectable, and tell the ComboBox which property of the selectable items you want to display.
Use the first method if you only want to display a constant array of strings. Fill ComboBox.Items. When an item is selected, use SelectedIndex to get the index of the selected string. Use ComboBox.Items[selectedIndex] to get the selected string.
If the string represents something more than just a string, for instance the text represents a Customer, or a Product. It is usually easier to use the DataSource method.
To do that, you use property ComboBox.DataSource to tell the ComboBox which Customersit should display. In ComboBox.ValueMember you tell the ComboBox which Customer poperty should be used to represent the Customer, for instance the name of the Customer.
Once the operator selected the name of the Customer, you get the complete Selected Customer using property ComboBox.SelectedItem:
List<Customer> availableCustomers = ...
ComboBox combo1 = new ComboBox(...);
combo1.ValueMember = nameof(Customer.Name); // the Customer property that you want to display
combo1.DataSource = availableCustomers;
After the operator selected an item, you can process the event, and fetch the selected customer immediately:
Customer selectedCustomer = (Customer)cmbo1.SelectedValue;
ProcessSelectedCustomer(selectedCustomer);
Of course you should only select a property that is unique. If you have two Customers named "Hans Brinker", operators wouldn't know which name represents which Customer.
Apart from the nice thing that you don't have to do a lookup from SelectedIndex to what this selected item represents (a Customer), you are independent of the order in which the Customers are displayed.
Another nice thing: if in future versions you want to change from ComboBox to ListBox, or maybe even to DataGridView, you won't have to change your model drastically: the control still shows a sequence of Customers, and once an operator selects something that represents this Customer (Name? Id?, DataGridView Row?), you get the complete Customer.
(1)ComboBox1.SelectedIndex starts from -1, when you are not selected, ComboBox1.SelectedIndex=-1
(2)When you click combobox1.items, SelectedText is always "".
This is because, at the time of these events(SelectedIndexChanged, SelectedValueChanged.. ), the previous SelectedText value has been cleared and the new value has not yet been set. You can use the SelectedItem property instead.
E.g:combobox1.SelectedItem
Please try the following code.
If ComboBox1.SelectedIndex = -1 Then
MessageBox.Show("No value selected")
Else
MessageBox.Show("Some value selected")
End If

Force a MultiLine TextBox Horizontal ScrollBar to the left

I have a MultiLine TextBox that is updated over a period of time as an app runs, and I've managed to make it so that the TextBox scrolls to the bottom, ensuring that the latest entry is always shown.
However, sometimes the text is quite long and goes off of the side of the TextBox, so the Horizontal ScrollBar scrolls to the right.
How can I amend the code below so that the ScrollBar is always to the left, meaning that the beginning of lines is always visible? Please note that I do not wish to wrap text, as I can't have one entry on multiple lines. Thanks.
Private Sub UpdateCurrentProgress(ByVal Text As String)
If Text = "" Then Exit Sub
Dim Textbox As TextBox = Me.txtCurrentProgress
If Textbox.Text <> "" Then Text = vbCrLf & Text
Textbox.AppendText(Text)
Textbox.Select(Textbox.TextLength, 0)
Textbox.ScrollToCaret()
End Sub
You can select the first char at the current line like this:
Me.TextBox1.Select(Me.TextBox1.GetFirstCharIndexOfCurrentLine(), 0)
If I understand your problem correctly, then you need to get first the last line index and then select the first char of that line.
Dim lineNumber = textBox1.Lines.Count()-1
textBox1.Select(textBox1.GetFirstCharIndexFromLine(lineNumber), 0)