VB.NET 2010 - I have a RichTextbox in which the user can manually enter data or copy/paste from another source. After the data is complete he hits go and a few key words are highlighted. My issue is that if he copy/pastes from another source the formatting also gets copied. Well sometimes the outside source has a white font and my textbox has a white background so it appears like he pasted nothing and he does it again and again.
What I'm looking for is a way to intercept the paste action into the textbox so that I can take that text and paste it as pure ASCII without formatting.
Edit after experimenting with KeyDown
Private Sub txtRch_KeyDown(sender As Object, e As System.Windows.Forms.KeyEventArgs) Handles txtRch.KeyDown
If e.Modifiers = Keys.Control AndAlso e.KeyCode = Keys.V Then
With txtRch
Dim i As Integer = .SelectionStart 'cache the current position
.Select(0, i) 'select text from start to current position
Dim s As String = .SelectedText 'copy that text to a variable
.Select(i, .TextLength) 'now select text from current position to end
Dim t As String = .SelectedText 'copy that text to a variable
Dim u As String = s & Clipboard.GetText(TextDataFormat.UnicodeText) & t 'now concatenate the first chunk, the new text, and the last chunk
.Clear() 'clear the textbox
.Text = u 'paste the new text back into textbox
.SelectionStart = i 'put cursor back to cached position
End With
'the event has been handled manually
e.Handled = True
End If
End Sub
This seems to work and all my text gets retained and its all ASCII. I think if I wanted to take a step further I could also take the font and forecolor of my RichTextbox, select all text, and then assign the font and forecolor to the selection.
In most cases, examining the KeyDown event should be good enough along with using a temporary RichTextBox to modify the incoming text:
Private Sub RichTextBox1_KeyDown(sender As Object, e As KeyEventArgs) _
Handles RichTextBox1.KeyDown
If e.Modifiers = Keys.Control AndAlso e.KeyCode = Keys.V Then
Using box As New RichTextBox
box.SelectAll()
box.SelectedRtf = Clipboard.GetText(TextDataFormat.Rtf)
box.SelectAll()
box.SelectionBackColor = Color.White
box.SelectionColor = Color.Black
RichTextBox1.SelectedRtf = box.SelectedRtf
End Using
e.Handled = True
End If
End Sub
Note: Missing any error checking.
Related
I have a problem, with DataGridView's CellFormatting. The cells are colored by the search result from a TextBox. When I search for 2 numbers together, they are no longer colored. What should I do?
I state that I am using CONCAT_WS to load the table in DataGridView. What can I do?
Private Sub DataGridView1_CellFormatting(sender As Object, e As DataGridViewCellFormattingEventArgs) Handles DataGridView1.CellFormatting
Try
If e.ColumnIndex = 3 And e.Value IsNot Nothing Or e.ColumnIndex = 4 And e.Value IsNot Nothing Or e.ColumnIndex = 5 And e.Value IsNot Nothing Or e.ColumnIndex = 6 And e.Value IsNot Nothing Or e.ColumnIndex = 7 And e.Value IsNot Nothing Then
If String.IsNullOrEmpty(txtRefreshFiltra.Text) Then
txtRefreshFiltra.Text = ""
End If
Dim sum6 As String = Convert.ToInt32(e.Value)
If sum6 = txtRefreshFiltra.Text Then
e.CellStyle.BackColor = Color.Gold
e.CellStyle.ForeColor = Color.Black
End If
End If
Catch ex As Exception
MsgBox(ex.Message) 'show error msg'
End Try
End Sub
My connection
Public Sub FilterData(ValueToSearch As String)
Try
Dim SearchQyery As String = "SELECT * FROM LottoDeaBendata WHERE CONCAT_WS([Estratto1],[Estratto2],[Estratto3],[Estratto4],[Estratto5])LIKE'%" & ValueToSearch & "%'"
Dim command As New SqlCommand(SearchQyery, connection)
connection.Open()
Dim table As New DataTable()
Dim adapter As New SqlDataAdapter(command)
adapter.Fill(table)
DataGridView1.DataSource = table
connection.Close()
Catch ex As Exception
MsgBox(ex.Message) 'show error msg'
End Try
End Sub
Upload by button
Private Sub btnFiltraDati_Click(sender As Object, e As EventArgs) Handles btnFiltraDati.Click
FilterData(txtRefreshFiltra.Text)
End Sub
There are a few things you may want to consider to color the cells as you describe. First, using the grids CellFormatting event may not necessarily be the best choice. This event will fire once for each cell when the data is loaded into the grid and this is fine and colors the cells as we want when the data is loaded, however, it also may fire if the user simply moves the cursor over a cell or the user scrolls the grid.
In both the cases of the user moving the cursor over a cell or scrolling the grid, clearly demonstrates that the cells will get re-colored unnecessarily. In other words, if the text in the text box has not changed or a cells value has not changed, then, re-coloring the cell(s) is superfluous.
Given this, the only drawback to NOT using the grids CellFormatting event is that our code will have to color the cells AFTER the grid is loaded with data. This means we will need a method to loop through all the rows of the grid to check and color the cells. This method to color all the cells is also going to be needed if the text in the text box changes. So, making this method makes sense so we can call it when the data is loaded and also when the text box text changes.
So given all this, to simplify things, I suggest you create a method that takes a single DataGridViewCell. The method will get the comma separated values from the text box and compare the cells value to the values in the text box and if one matches, then we simply color the cell, otherwise do not color the cell.
This method is below. First, we check if the cell is not null and actually has some value. Then, we take the string in the text box and split it on commas. Then we start a loop through all the values in the split string from the text box and if a match is found, then we simply color the cell and exit the for each loop.
Private Sub ColorCell(cell As DataGridViewCell)
If (cell.Value IsNot Nothing) Then
Dim target = cell.Value.ToString()
If (Not String.IsNullOrEmpty(target)) Then
cell.Style.BackColor = Color.White
cell.Style.ForeColor = Color.Black
Dim split = txtRefreshFiltra.Text.Trim().Split(",")
For Each s As String In split
If (target = s.Trim()) Then
cell.Style.BackColor = Color.Gold
cell.Style.ForeColor = Color.Black
Exit For
End If
Next
End If
End If
End Sub
The method above should simplify looping through all the rows in the grid to color the proper cells. This method may look something like below and we would call this method once after the data is loaded into the grid and also when the text in the text box changes.
Private Sub ColorAllCells()
For Each row As DataGridViewRow In DataGridView1.Rows
ColorCell(row.Cells(3))
ColorCell(row.Cells(4))
ColorCell(row.Cells(5))
ColorCell(row.Cells(6))
ColorCell(row.Cells(7))
Next
End Sub
Lastly, the two event methods that we need to capture when the user changes a cells value in the grid in addition to when the user changes the text in the text box.
Private Sub txtRefreshFiltra_TextChanged(sender As Object, e As EventArgs) Handles txtRefreshFiltra.TextChanged
ColorAllCells()
End Sub
Private Sub DataGridView1_CellValueChanged(sender As Object, e As DataGridViewCellEventArgs) Handles DataGridView1.CellValueChanged
If (e.RowIndex >= 0) Then
If (e.ColumnIndex = 3 Or e.ColumnIndex = 4 Or e.ColumnIndex = 5 Or e.ColumnIndex = 6 Or e.ColumnIndex = 7) Then
ColorCell(DataGridView1.Rows(e.RowIndex).Cells(e.ColumnIndex))
End If
End If
End Sub
Edit per OP comment…
There are definitely a couple of things we can do to speed up the current code above, like take out the call to ColorAllCells in the text boxes TextChanged event.
The TextChanged event will fire when the user types a single character. Example, if the user wants to color the cells that are “55”, then, when the user types the first “5” into the text box… then the TextChanged event will fire and the code will color all the cells with “5”. Then when the user types the second “5”, the cells will be un-colored/colored again.
So, one way we can prevent the unnecessary coloring as described above is to NOT call the ColorAllCells method in the text boxes TextChanged event and simply put the ColorAllCells method into a button click. In other words, the user types what they want into the text box… THEN clicks a button to color the cells.
In addition, if you look at the ColorCell method, you may note that each time the method is called, the code is splitting the same string over and over with … Dim split = txtRefreshFiltra.Text.Trim().Split(",") … this is potentially redundant in a sense that the text … txtRefreshFiltra.Text may not have changed.
Therefore, to remedy this and only split the txtRefreshFiltra.Text when needed, we will use a global variable called something like currentSplit that holds the current split of the text box. Then we would “update” the currentSplit variable only when needed… like in its TextChanged event.
This should somewhat speed things up. In my small tests, it took approximately 10 seconds to color the cells the FIRST time. Subsequent coloring of the cells when the text box value was changed took less than 1 second.
First make a global variable to hold the current text boxes split values…
Dim currentSplit As String()
Then change the other methods as shown below…
Private Sub Form1_Load(sender As Object, e As EventArgs) Handles MyBase.Load
Dim dt = GetDT()
DataGridView1.DataSource = dt
currentSplit = txtRefreshFiltra.Text.Trim().Split(",")
End Sub
Private Sub ColorCell(cell As DataGridViewCell)
If (cell.Value IsNot Nothing) Then
Dim target = cell.Value.ToString()
If (Not String.IsNullOrEmpty(target)) Then
cell.Style.BackColor = Color.White
cell.Style.ForeColor = Color.Black
For Each s As String In currentSplit
If (target = s.Trim()) Then
cell.Style.BackColor = Color.Gold
cell.Style.ForeColor = Color.Black
Exit For
End If
Next
End If
End If
End Sub
Private Sub txtRefreshFiltra_TextChanged(sender As Object, e As EventArgs) Handles txtRefreshFiltra.TextChanged
currentSplit = txtRefreshFiltra.Text.Trim().Split(",")
End Sub
And finally, a button click event to color the cells. I added a stop watch to time how long it takes to color the cells.
Private Sub Button1_Click(sender As Object, e As EventArgs) Handles Button1.Click
Dim sw As Stopwatch = New Stopwatch()
Debug.WriteLine("Starting coloring of cells -------")
sw.Start()
ColorAllCells()
sw.Stop()
Debug.WriteLine("It took: " + sw.Elapsed.TotalSeconds.ToString() + " to color the cells of 100,000 rows with 10 columns")
End Sub
I am looking to change textbox fore and back colors of multiple textboxes based on a value if any one of the textboxes change it's value either by user input or reading from the DB.
I am not sure how to implement the code once an individual textbox has a change. The below code is as far as I got as I do not know how to implement it to work. Can someone assist?
Private Sub DiffCalcColor_TextChanged(sender As Object, e As EventArgs) Handles tbPMDiffCalc.TextChanged, tbLHDiffCalc.TextChanged, tbRFDiffCalc.TextChanged, tbFSDiffCalc.TextChanged, tbFSADiffCalc.TextChanged
Dim tb = DirectCast(sender, TextBox)
Dim text = tb.Text.Replace("$", "")
Dim number As Decimal
Decimal.TryParse(text, number)
Select Case number
Case < 0D : tb.ForeColor = Color.DarkRed
tb.BackColor = Color.White
Case > 0D : tb.ForeColor = Color.Green
tb.BackColor = Color.White
Case = 0D : tb.ForeColor = Color.DimGray
tb.BackColor = Color.Gainsboro
Case Else
Exit Select
End Select
End Sub
If you want to handle the same event for multiple controls with a single method then you simply include all those controls in the Handles clause, e.g.
Private Sub TextBoxes_TextChanged(sender As Object, e As EventArgs) Handles TextBox1.TextChanged,
TextBox2.TextChanged
Dim eventRaiser = DirectCast(sender, TextBox)
'Get the text that just changed.
Dim text = eventRaiser.Text
Dim number As Decimal
'Try to convert it to a number.
Decimal.TryParse(text, number)
'Use the number to decide how to format.
If number = Decimal.Zero Then
'...
Else
'...
End If
End Sub
You can do that manually or you can let the designer do it for you. To do the latter, start by selecting the multiple controls in the designer, then open the Properties window, click the Events button on the toolbar, then double-click the appropriate event. That will generate an event handler, much like double-clicking on a single control does, but it will add all the selected controls to the Handles clause. It also allows you to generate a handler for any event, rather than just the default event. To add a control to that Handles clause, you can select one or more controls, select the event and then select an existing event handler from the drop-down.
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
I have a textbox in a vb form and I want to limit the range of characters that the user can put into the textbox to:" abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ1234567890^-*().". The textbox is to insert SI Units into a database so i need consistent syntax. If the user types an invalid character into the textbox I would like the textbox to refuse to insert it, or remove it straight away, leaving the cursor in the same position within the textbox. I would also like the textbox to replace "/" with "^(-" and place the cursor before this.
I have found some code elsewhere which I have edited to do this but the code is bad, it activates on text changed within the textbox. This causes the code to fail, when the user inputs a disallowed value the code it activates itself when it tries to changes the text within the textbox.
Here is my code, the textbox starts with the contents "enter SI Units" from the form designer.
Private Sub TxtQuantityTextChanged(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles txtSIUnit.TextChanged
If txtSIUnit.Text = "Enter SI Units" Then
Exit Sub
End If
Dim charactersAllowed As String = " abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ1234567890^-*()."
Dim Text As String = txtSIUnit.Text
Dim Letter As String
Dim SelectionIndex As Integer = txtSIUnit.SelectionStart
Dim Change As Integer
Letter = txtSIUnit.Text.Substring(SelectionIndex - 1, 1)
If Letter = "/" Then
Text = Text.Replace(Letter, "^(-")
SelectionIndex = SelectionIndex - 1
End If
Letter = txtSIUnit.Text.Substring(SelectionIndex - 1, 1)
If charactersAllowed.Contains(Letter) = False Then
Text = Text.Replace(Letter, String.Empty)
Change = 1
End If
txtSIUnit.Text = Text
txtSIUnit.Select(SelectionIndex - Change, 0)
If txtQuantity.Text <> "Enter Quantity" Then
If cmbStateRateSumRatio.SelectedIndex <> -1 Then
bttAddQUAtoDatabase.Enabled = True
End If
End If
End Sub`
Thanks for you help.
Use the KeyPress event. Set e.Handled to true if you don't like the character. It's a one-liner:
Private Const AllowedChars = " abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ1234567890^-*()."
Private Sub TextBox1_KeyPress(ByVal sender As Object, ByVal e As PressEventArgs) Handles TextBox1.KeyPress
If e.KeyChar >= " "c AndAlso Not AllowedChars.Contains(e.KeyChar) Then e.Handled = True
End Sub
In the textbox's KeyDown event, check e.KeyCode. This lets you prevent certain characters from being handled. There's an example on the KeyDown documentation.
I'm new to the VB applications.My basic background is C.I just installed VB and learning stuff from google and microsoft help center. and I'm having fun with the things I'm doing but I got stucked up at one point and thats at richtext box.Is there any way to keep track of Rich textbox text in VB? So that I can append some text when user hits new line (i.e enter ) and do some task when he hits backspace. How do i keep track of richtextbox.?
I found
stringer = RichTextBox1.Lines(0) to read lines
& vbNewLine for new line
How do i read that user hit the new line character or backspace in vb rich textbox? because as far in C i used to do like these
if a = 13; \\ ascii for new line and 8 for backspace
I just want to do some task when user hits new line but I am unable to figure it out what the condition to be made.and Any good links for vb and documents on VB or on its windows application would be appreciated Too. Thank you in advance
You will want to link into the KeyDown event for the RichTextBox. Within this event you can modify the Text of the current line. Sample code for adding text to a line is:
Private Sub RichTextBox1_KeyDown(ByVal sender As Object, ByVal e As System.Windows.Forms.KeyEventArgs) Handles RichTextBox1.KeyDown
Dim textToAdd As String = " ** text to add **"
'Fire when the Enter key is pressed
If e.KeyCode = Keys.Enter Then
'Get the current cursor position
Dim cursorPos As Integer = RichTextBox1.SelectionStart
'Get the current line index
Dim index As Integer = RichTextBox1.GetLineFromCharIndex(cursorPos)
'Load all the lines into a string array
'This has to be done since editing via RichTextBox1.Lines(index) = "" doesn't always work
Dim lines() As String = RichTextBox1.Lines
'Add the text to the correct line
lines(index) &= textToAdd
'Assign the text back to the RichTextBox
RichTextBox1.Lines = lines
'Move the cursor to the correct position
RichTextBox1.SelectionStart = cursorPos + textToAdd.Length
End If
End Sub
All you need to do is check if the Enter or BackSpace key was pressed, like this:
Private Sub RichTextBox1_KeyDown(ByVal sender As Object, ByVal e As System.Windows.Forms.KeyEventArgs) Handles RichTextBox1.KeyDown
Select Case e.KeyCode
Case Keys.Enter
'Do stuff when Enter was pressed
Case Keys.Back
'Do stuff when BackSpace was pressed
End Select
End Sub
Note that Select Case is the same as the switch in C.