Как добавить текст в RichTextBox без прокрутки и потери выделения? - PullRequest
7 голосов
/ 01 июля 2011

Мне нужно добавить текст в RichTextBox и выполнить его без прокрутки текстового поля или потери текущего выделения текста, возможно ли это?

Ответы [ 5 ]

14 голосов
/ 01 июля 2011

RichTextBox в WinForms очень радует, когда вы играете с методами text и select-text.

У меня есть стандартная замена для отключения рисования и прокрутки с помощью следующего кода:

class RichTextBoxEx: RichTextBox
{
  [DllImport("user32.dll")]
  static extern IntPtr SendMessage(IntPtr hWnd, Int32 wMsg, Int32 wParam, ref Point lParam);

  [DllImport("user32.dll")]
  static extern IntPtr SendMessage(IntPtr hWnd, Int32 wMsg, Int32 wParam, IntPtr lParam);

  const int WM_USER = 0x400;
  const int WM_SETREDRAW = 0x000B;
  const int EM_GETEVENTMASK = WM_USER + 59;
  const int EM_SETEVENTMASK = WM_USER + 69;
  const int EM_GETSCROLLPOS = WM_USER + 221;
  const int EM_SETSCROLLPOS = WM_USER + 222;

  Point _ScrollPoint;
  bool _Painting = true;
  IntPtr _EventMask;
  int _SuspendIndex = 0;
  int _SuspendLength = 0;

  public void SuspendPainting()
  {
    if (_Painting)
    {
      _SuspendIndex = this.SelectionStart;
      _SuspendLength = this.SelectionLength;
      SendMessage(this.Handle, EM_GETSCROLLPOS, 0, ref _ScrollPoint);
      SendMessage(this.Handle, WM_SETREDRAW, 0, IntPtr.Zero);
      _EventMask = SendMessage(this.Handle, EM_GETEVENTMASK, 0, IntPtr.Zero);
      _Painting = false;
    }
  }

  public void ResumePainting()
  {
    if (!_Painting)
    {
      this.Select(_SuspendIndex, _SuspendLength);
      SendMessage(this.Handle, EM_SETSCROLLPOS, 0, ref _ScrollPoint);
      SendMessage(this.Handle, EM_SETEVENTMASK, 0, _EventMask);
      SendMessage(this.Handle, WM_SETREDRAW, 1, IntPtr.Zero);
      _Painting = true;
      this.Invalidate();
    }
  }
}

и затем из моей формы я могу с радостью получить элемент управления richtextbox без мерцания:

richTextBoxEx1.SuspendPainting();
richTextBoxEx1.AppendText("Hey!");
richTextBoxEx1.ResumePainting();
0 голосов
/ 26 марта 2019

Изменен код LarsTech для автоматической остановки автоматической прокрутки, если курсор не находится на последней позиции в RichTextBox.Также решена проблема с вводом цветного текста.Чтобы возобновить прокрутку, поместите курсор в последнюю позицию (Ctrl-END)

    class RichTextBoxEx : RichTextBox
    {
        [DllImport("user32.dll")]
        private static extern IntPtr SendMessage(IntPtr hWnd, Int32 wMsg, Int32 wParam, ref Point lParam);

        [DllImport("user32.dll")]
        private static extern IntPtr SendMessage(IntPtr hWnd, Int32 wMsg, Int32 wParam, IntPtr lParam);

        [DllImport("user32")]
        private static extern int GetCaretPos(out Point p);

        const int WM_USER = 0x400;
        const int WM_SETREDRAW = 0x000B;
        const int EM_GETEVENTMASK = WM_USER + 59;
        const int EM_SETEVENTMASK = WM_USER + 69;
        const int EM_GETSCROLLPOS = WM_USER + 221;
        const int EM_SETSCROLLPOS = WM_USER + 222;

        private Point oScrollPoint;
        private bool bPainting = true;
        private IntPtr oEventMask;
        private int iSuspendCaret;
        private int iSuspendIndex;
        private int iSuspendLength;
        private bool bWasAtEnd;
        private Color _selColor = Color.Black;

        public int CaretIndex
        {
            get
            {
                Point oCaret;
                GetCaretPos(out oCaret);
                return this.GetCharIndexFromPosition(oCaret);
            }
        }

        new public Color SelectionColor { get { return _selColor; } set { _selColor = value; } }
        new public void AppendText(string text)  // overwrites RichTextBox.AppendText
        {
            if (this.SelectionStart >= this.TextLength)
            {
                base.SelectionColor = _selColor;
                base.AppendText(text);
            }
            else
            {
                var selStart = this.SelectionStart;
                var selLength = this.SelectionLength;
                SuspendPainting();
                this.Select(this.TextLength, 0);
                base.SelectionColor = _selColor;
                base.AppendText(text);
                this.Select(selStart, selLength);
                ResumePainting();
            }
        }
        private void SuspendPainting()
        {
            if (this.bPainting)
            {
                this.iSuspendCaret = this.CaretIndex;
                this.iSuspendIndex = this.SelectionStart;
                this.iSuspendLength = this.SelectionLength;
                this.bWasAtEnd = this.iSuspendIndex + this.iSuspendLength == this.TextLength;

                SendMessage(this.Handle, EM_GETSCROLLPOS, 0, ref this.oScrollPoint);
                SendMessage(this.Handle, WM_SETREDRAW, 0, IntPtr.Zero);
                this.oEventMask = SendMessage(this.Handle, EM_GETEVENTMASK, 0, IntPtr.Zero);
                this.bPainting = false;
            }
        }

        private void ResumePainting()
        {
            if (!this.bPainting)
            {
                if (this.iSuspendLength == 0)
                {
                    if (!bWasAtEnd)
                    {
                        this.Select(this.iSuspendIndex, 0);
                    }
                }
                else
                {
                    // Original selection was to end of text
                    if (bWasAtEnd)
                    {
                        // Maintain end of selection at end of new text
                        this.iSuspendLength = this.TextLength - this.iSuspendIndex;
                    }

                    if (this.iSuspendCaret > this.iSuspendIndex)
                    {
                        // Forward select (caret is at end)
                        this.Select(this.iSuspendIndex, this.iSuspendLength);
                    }
                    else
                    {
                        // Reverse select (caret is at start)
                        this.Select(this.iSuspendIndex + this.iSuspendLength, -this.iSuspendLength);
                    }
                }
                SendMessage(this.Handle, EM_SETSCROLLPOS, 0, ref this.oScrollPoint);
                SendMessage(this.Handle, EM_SETEVENTMASK, 0, this.oEventMask);
                SendMessage(this.Handle, WM_SETREDRAW, 1, IntPtr.Zero);
                this.bPainting = true;
                this.Invalidate();
            }
        }
    }
0 голосов
/ 23 февраля 2018

Это решение почти точно, за исключением того, что оно неправильно обрабатывает обратные выделения (где курсор находится в начале выделения, а не в конце - например, SHIFT + LEFT или перетаскивание мышью вверх используется для выделения текста).

Вот улучшенная версия со следующими добавленными функциями:

  • Если курсор вставляется в конец текста, он остается там, при необходимости прокручиваясь.
  • Если исходный выбор начинался или заканчивался на последнем символе, любой добавленный текст включается в новый выбор.

Это означает, что вы можете поместить курсор в конец добавляемого текста и контролировать текст (например, мониторинг файла журнала).Это также означает, что вы можете нажать CTRL + A, чтобы выделить все, и любой добавленный текст будет автоматически включен в ваш выбор.

class RichTextBoxEx : RichTextBox
{
    [DllImport("user32.dll")]
    private static extern IntPtr SendMessage(IntPtr hWnd, Int32 wMsg, Int32 wParam, ref Point lParam);

    [DllImport("user32.dll")]
    private static extern IntPtr SendMessage(IntPtr hWnd, Int32 wMsg, Int32 wParam, IntPtr lParam);

    [DllImport("user32")]
    private static extern int GetCaretPos(out Point p);

    const int WM_USER = 0x400;
    const int WM_SETREDRAW = 0x000B;
    const int EM_GETEVENTMASK = WM_USER + 59;
    const int EM_SETEVENTMASK = WM_USER + 69;
    const int EM_GETSCROLLPOS = WM_USER + 221;
    const int EM_SETSCROLLPOS = WM_USER + 222;

    private Point oScrollPoint;
    private bool bPainting = true;
    private IntPtr oEventMask;
    private int iSuspendCaret;
    private int iSuspendIndex;
    private int iSuspendLength;
    private bool bWasAtEnd;

    public int CaretIndex
    {
        get
        {
            Point oCaret;
            GetCaretPos(out oCaret);
            return this.GetCharIndexFromPosition(oCaret);
        }
    }

    public void AppendTextWithoutScroll(string text)
    {
        this.SuspendPainting();
        this.AppendText(text);
        this.ResumePainting();
    }

    private void SuspendPainting()
    {
        if (this.bPainting)
        {
            this.iSuspendCaret = this.CaretIndex;
            this.iSuspendIndex = this.SelectionStart;
            this.iSuspendLength = this.SelectionLength;
            this.bWasAtEnd = this.iSuspendIndex + this.iSuspendLength == this.TextLength;

            SendMessage(this.Handle, EM_GETSCROLLPOS, 0, ref this.oScrollPoint);
            SendMessage(this.Handle, WM_SETREDRAW, 0, IntPtr.Zero);
            this.oEventMask = SendMessage(this.Handle, EM_GETEVENTMASK, 0, IntPtr.Zero);
            this.bPainting = false;
        }
    }

    private void ResumePainting()
    {
        if (!this.bPainting)
        {
            if (this.iSuspendLength == 0)
            {
                if (!bWasAtEnd)
                {
                    this.Select(this.iSuspendIndex, 0);
                }
            }
            else
            {
                // Original selection was to end of text
                if (bWasAtEnd)
                {
                    // Maintain end of selection at end of new text
                    this.iSuspendLength = this.TextLength - this.iSuspendIndex;
                }

                if (this.iSuspendCaret > this.iSuspendIndex)
                {
                    // Forward select (caret is at end)
                    this.Select(this.iSuspendIndex, this.iSuspendLength);
                }
                else
                {
                    // Reverse select (caret is at start)
                    this.Select(this.iSuspendIndex + this.iSuspendLength, -this.iSuspendLength);
                }
            }
            SendMessage(this.Handle, EM_SETSCROLLPOS, 0, ref this.oScrollPoint);
            SendMessage(this.Handle, EM_SETEVENTMASK, 0, this.oEventMask);
            SendMessage(this.Handle, WM_SETREDRAW, 1, IntPtr.Zero);
            this.bPainting = true;
            this.Invalidate();
        }
    }
}
0 голосов
/ 30 ноября 2017

на основе статьи LarsTech здесь что-то приятное:

using System;
using System.Runtime.InteropServices;
using System.Windows.Forms;
using System.Drawing;

namespace yournamespace
{
    class RichTextBoxEx : RichTextBox
    {
        [DllImport("user32.dll")]
        static extern IntPtr SendMessage(IntPtr hWnd, Int32 wMsg, Int32 wParam, ref Point lParam);

        [DllImport("user32.dll")]
        static extern IntPtr SendMessage(IntPtr hWnd, Int32 wMsg, Int32 wParam, IntPtr lParam);

        const int WM_USER = 0x400;
        const int WM_SETREDRAW = 0x000B;
        const int EM_GETEVENTMASK = WM_USER + 59;
        const int EM_SETEVENTMASK = WM_USER + 69;
        const int EM_GETSCROLLPOS = WM_USER + 221;
        const int EM_SETSCROLLPOS = WM_USER + 222;

        Point _ScrollPoint;
        bool _Painting = true;
        IntPtr _EventMask;
        int _SuspendIndex = 0;
        int _SuspendLength = 0;

        public bool Autoscroll = true;

        public void SuspendPainting()
        {
            if (_Painting)
            {
                _SuspendIndex = this.SelectionStart;
                _SuspendLength = this.SelectionLength;
                SendMessage(this.Handle, EM_GETSCROLLPOS, 0, ref _ScrollPoint);
                SendMessage(this.Handle, WM_SETREDRAW, 0, IntPtr.Zero);
                _EventMask = SendMessage(this.Handle, EM_GETEVENTMASK, 0, IntPtr.Zero);
                _Painting = false;
            }
        }

        public void ResumePainting()
        {
            if (!_Painting)
            {
                this.Select(_SuspendIndex, _SuspendLength);
                SendMessage(this.Handle, EM_SETSCROLLPOS, 0, ref _ScrollPoint);
                SendMessage(this.Handle, EM_SETEVENTMASK, 0, _EventMask);
                SendMessage(this.Handle, WM_SETREDRAW, 1, IntPtr.Zero);
                _Painting = true;
                this.Invalidate();
            }
        }

        new public void AppendText(string text)  // overwrites RichTextBox.AppendText
        {
            if (Autoscroll)
                base.AppendText(text);
            else
            {
                SuspendPainting();
                base.AppendText(text);
                ResumePainting();
            }
        }
    }
}

вы можете использовать это так:

var textbox = new RichTextBoxEx();
textbox.Autoscroll = false;

textbox.AppendText("Hi");
0 голосов
/ 01 июля 2011

Это должно делать то, что вы хотите:

        Dim tempStart As Int32
    Dim tempLength As Int32

    tempStart = RichTextBox1.SelectionStart
    tempLength = RichTextBox1.SelectionLength

    RichTextBox1.Text += "dsfkljwerhsdlf"

    RichTextBox1.SelectionStart = tempStart
    RichTextBox1.SelectionLength = tempLength
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...