У меня есть элемент управления, унаследованный от RichTextBox, и идея состоит в том, что пользователь вводит числа в строке, а элементы управления окрашивают каждую строку как прочитанную или зеленую в зависимости от того, является ли текст в строке действительным числом.
Вкл. TextChanged
проверяется каждая строка, и с помощью SelectionColor
цвет каждой строки корректируется соответствующим образом. Пожалуйста, найдите полный код ниже.
Чтобы сохранить эту скорость, я приостанавливаю перерисовку элемента управления перед обновлением цветов, отправляя сообщение WM_SETREDRAW, как описано в различных вопросах / ответах на этом сайте, например, В частности, о RichTextBox .
Я долгое время использовал это без проблем, но недавно повторно использовал элемент управления в проекте, нацеленном на .NET Framework 4.7.2 вместо более старых платформ, таких как 4.5 или 4.6.
Здесь я сталкиваюсь с проблемой графических сбоев, как только элемент управления содержит достаточно строк, чтобы вызвать прокрутку. Цвета не применяются правильно, появляются призрачные курсоры и так далее. Я пытался показать это на картинке:
Единственное, что я изменил между вторым и третьим рисунком, это изменил целевую платформу на 4.6.2 и перекомпилировал.
У кого-то есть идея, что вызывает это и как обойти проблему?
Пожалуйста, не стесняйтесь использовать VB или C # на ваш вкус, я не сужу: -)
Вот код элемента управления, который я использовал для воспроизведения поведения:
Public Class RichtextNumberlist
Inherits RichTextBox
Private Sub tbValues_TextChanged(sender As Object, e As EventArgs) Handles Me.TextChanged
SuspendDrawing(Me)
UpdateColor(Me)
ResumeDrawing(Me)
End Sub
<DllImport("user32.dll")>
Private Shared Function SendMessage(ByVal hWnd As IntPtr, ByVal Msg As Integer, ByVal wParam As Boolean, ByVal lParam As IntPtr) As Integer
End Function
Private Const WM_SETREDRAW As Integer = 11
Public Sub SuspendDrawing(ByVal Target As Control)
SendMessage(Me.Handle, WM_SETREDRAW, False, 0)
End Sub
Public Sub ResumeDrawing(ByVal Target As Control)
SendMessage(Me.Handle, WM_SETREDRAW, True, 0)
Target.Invalidate()
End Sub
Private Function CheckLine(line As String) As Boolean
Dim d As Double
Return Double.TryParse(line, d)
End Function
Private Sub UpdateColor(tbValues As RichTextBox)
Dim t = Threading.Thread.CurrentThread
Console.WriteLine($"Updating color from thread STA={t.GetApartmentState().ToString()}, BG={t.IsBackground}")
'Save selection parameters to reset them afterwards
Dim oldsel As Integer = tbValues.SelectionStart
Dim oldsell As Integer = tbValues.SelectionLength
Dim pos As Integer = 0
Dim lCount = tbValues.Lines.Count
Dim lines = tbValues.Lines
For i = 0 To lCount - 1
'Set selection on the ith line
tbValues.SelectionStart = pos
tbValues.SelectionLength = lines(i).Length
Dim lineok = CheckLine(lines(i))
'Adjust the color accordingly
If lineok Then
tbValues.SelectionColor = Color.ForestGreen
Else
tbValues.SelectionColor = Color.Red
End If
'Move forward
pos += lines(i).Length + 1
Next
'Reset the selection
tbValues.SelectionStart = oldsel
tbValues.SelectionLength = oldsell
End Sub
End Class