Сбой WM_SETREDRAW в RichTextBox в .NET Framework 4.7.2, но работает в 4.6.2 - PullRequest
0 голосов
/ 03 апреля 2019

У меня есть элемент управления, унаследованный от RichTextBox, и идея состоит в том, что пользователь вводит числа в строке, а элементы управления окрашивают каждую строку как прочитанную или зеленую в зависимости от того, является ли текст в строке действительным числом.

Вкл. TextChanged проверяется каждая строка, и с помощью SelectionColor цвет каждой строки корректируется соответствующим образом. Пожалуйста, найдите полный код ниже.

Чтобы сохранить эту скорость, я приостанавливаю перерисовку элемента управления перед обновлением цветов, отправляя сообщение WM_SETREDRAW, как описано в различных вопросах / ответах на этом сайте, например, В частности, о RichTextBox .

Я долгое время использовал это без проблем, но недавно повторно использовал элемент управления в проекте, нацеленном на .NET Framework 4.7.2 вместо более старых платформ, таких как 4.5 или 4.6.

Здесь я сталкиваюсь с проблемой графических сбоев, как только элемент управления содержит достаточно строк, чтобы вызвать прокрутку. Цвета не применяются правильно, появляются призрачные курсоры и так далее. Я пытался показать это на картинке:

enter image description here

Единственное, что я изменил между вторым и третьим рисунком, это изменил целевую платформу на 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
...