Reputation: 1151
I'm using a visible RitchTextBox to write an automatic log and I don't want that the user change the cursor position. I can't just disable the control because it loses its background color (when the log is full it's saved as RTF file).
I've already set ReadOnly = True
and ShorcutsEnabled = False
.
My code:
Protected Friend Sub PrintPort(ByVal NewText As String, Optional ByVal ForeColor As Color = Nothing, Optional ByVal NewLine As Boolean = True)
If Me.InvokeRequired Then
Dim Txt As New PrintSmsLogDelegate(AddressOf PrintPort)
Me.BeginInvoke(Txt, NewText, ForeColor, NewLine)
Else
If ClearLogFl Then
ClearLogFl = False
Me.RTB1.Clear()
End If
If NewText.Length < 1 Then
Return
End If
If ForeColor = Nothing Then
ForeColor = Color.White
End If
If NewLine Then
If Me.RTB1.TextLength > 1 Then
NewText = vbCrLf + NewText
End If
End If
Me.RTB1.SelectionColor = ForeColor 'Set color
Me.RTB1.SelectedText = NewText 'Add text
If Me.LogAutoScrollChk.Checked And NewText.Contains(vbLf) Then
Me.RTB1.ScrollToCaret()
End If
End If
End Sub
Upvotes: 0
Views: 856
Reputation: 32288
An example, using a Threaded Timer (System.Timers.Timer
) to simulate a method called from a Thread other than the UI Thread.
The RichTexBox Control needs to refuse User interaction: neither the text or the caret position can be modified and the User cannot interfere with the scrolling procedure, activated or not.
We can set the RichTextBox as ReadOnly
and remove the Scrollbars (neither of these are actually required, but it's a better option, IMO).
In the Enter
event of the RicheTextBox, the Form.ActiveControl is set to null
(Nothing
), so the RichTextBox is not the ActiveControl
anymore, thus it doesn't receive the Keyboard or Mouse Input.
Note that with this setup, there's no chance to directly interact with the RTB, even if it's the only Control in the Form that can receive the Focus.
Since your PrintPort()
method is apparently called from another Thread, you need to Invoke the UI Thread to append to the Control.
BeginInvoke() can simplify the invocation procedure, using a Lambda as the Action delegate.
There's no need to check InvokeRequired
, BeginInvoke()
can be safely called also from the same Thread where the invocation is performed (the UI Thread).
Private Shared rndColor As New Random()
Private threadedTimer As System.Timers.Timer = Nothing
Protected Overrides Sub OnLoad(e As EventArgs)
MyBase.OnLoad(e)
rtb1.ReadOnly = True
rtb1.ScrollBars = RichTextBoxScrollBars.None
AddHandler rtb1.Enter, Sub() ActiveControl = Nothing
threadedTimer = New System.Timers.Timer() With {.Interval = 1000}
AddHandler threadedTimer.Elapsed, AddressOf TimerElapsedHandler
threadedTimer.Start()
End Sub
Private Sub TimerElapsedHandler(s As Object, e As EventArgs)
BeginInvoke(New Action(
Sub()
If Not rtb1.IsHandleCreated Then Return
Dim rndValue = rndColor.Next(2)
rtb1.SelectionStart = rtb1.TextLength
rtb1.SelectionColor = If(rndValue = 1, Color.Orange, Color.YellowGreen)
rtb1.AppendText(If(rndValue = 1, "Some other Text", "Some new text") & VbLf)
If LogAutoScrollChk.Checked Then rtb1.ScrollToCaret()
End Sub)
)
End Sub
Protected Overrides Sub OnFormClosing(e As FormClosingEventArgs)
threadedTimer.Stop()
RemoveHandler threadedTimer.Elapsed, AddressOf TimerElapsedHandler
threadedTimer.Dispose()
MyBase.OnFormClosing(e)
End Sub
Upvotes: 2
Reputation: 81675
You can make your own RichTextBox for this. I converted the c# answer in make richtextbox not respond to mouse events and added the handling of the Paging keys:
Public Class DisplayBox
Inherits RichTextBox
Private Const WM_SETFOCUS As Integer = &H7
Private Const WM_ENABLE As Integer = &HA
Private Const WM_SETCURSOR As Integer = &H20
Protected Overrides Sub WndProc(ByRef m As System.Windows.Forms.Message)
If Not (m.Msg = WM_SETFOCUS OrElse m.Msg = WM_ENABLE OrElse m.Msg = WM_SETCURSOR) Then
MyBase.WndProc(m)
End If
End Sub
Protected Overrides Sub OnKeyDown(e As KeyEventArgs)
If (e.KeyCode = Keys.PageDown Or e.KeyCode = Keys.PageUp) Then
e.Handled = True
End If
MyBase.OnKeyDown(e)
End Sub
End Class
Works when the ReadOnly = True
and ScrollBars = None
properties are set.
Upvotes: 1