c# RTB - вставить обычный текст без цветов/шрифтов?

Я использую объект Rich Text в своем приложении С#. Единственная проблема, с которой я сталкиваюсь, заключается в том, что когда пользователь вставляет отформатированный текст из другого приложения, он остается отформатированным, чего у меня не может быть. Есть ли способ вставить только строку и игнорировать форматирование? Спасибо!


person Thomas    schedule 10.01.2010    source источник
comment
@Tomas Добавлен второй пример кода, который вставляет содержимое буфера обмена в текущую точку вставки в RichTextBox, а затем обновляет точку вставки сразу после добавленного текста. Второй пример также иллюстрирует использование макета Suspend/Resume, чтобы избежать эффекта мерцания при перенастройке содержимого RichTextBox. Будьте уверены и протестируйте с различными типами форматированного ввода: опять же, это НЕ полностью протестировано до уровня, на котором я бы использовал его в производственном коде без дальнейшего тестирования.   -  person BillW    schedule 11.01.2010


Ответы (10)


Предполагая WinForms: попробуйте следующее: определите RichTextBox с обработчиком событий KeyDown следующим образом:

Пример только для добавления:

    private void richTextBox1_KeyDown(object sender, KeyEventArgs e)
    {
        if (e.Control && e.KeyCode == Keys.V) 
        {
            richTextBox1.Text += (string)Clipboard.GetData("Text"); 
            e.Handled = true; 
        }
    }

[Редактировать]

Пример добавления буфера обмена RTF в RichTextBox в текущей точке вставки (начало выделения):

private void richTextBox1_KeyDown(object sender, KeyEventArgs e) 
{ 
    if (e.Control && e.KeyCode == Keys.V)  
    { 
            // suspend layout to avoid blinking
            richTextBox2.SuspendLayout();

            // get insertion point
            int insPt = richTextBox2.SelectionStart;

            // preserve text from after insertion pont to end of RTF content
            string postRTFContent = richTextBox2.Text.Substring(insPt);

            // remove the content after the insertion point
            richTextBox2.Text = richTextBox2.Text.Substring(0, insPt);

            // add the clipboard content and then the preserved postRTF content
            richTextBox2.Text += (string)Clipboard.GetData("Text") + postRTFContent;

            // adjust the insertion point to just after the inserted text
            richTextBox2.SelectionStart = richTextBox2.TextLength - postRTFContent.Length;

            // restore layout
            richTextBox2.ResumeLayout();

            // cancel the paste
            e.Handled = true;
    } 
} 

[Конец редактирования]

Примечание 0. Вставленный текст будет предполагать текущие настройки стиля, действующие для RichTextBox: если для параметра «Цвет переднего плана» установлено значение «Синий»: вставленный текст будет синим.

Примечание 1: Это то, что я быстро собрал и протестировал всего несколько раз, создав несколько разноцветных и странно отформатированных RTF для буфера обмена с помощью WordPad: затем вставив в RichTextBox1 во время выполнения: он удалил все цвет, отступ и т.д.

Поскольку он не полностью протестирован, соблюдайте осторожность.

Примечание 2. Очевидно, что это не будет обрабатывать случай «Вставить» или «Вставить через контекстное меню».

Приветствую всю критику этого ответа и немедленно уберу его, если он не «на высоте».

person BillW    schedule 10.01.2010
comment
Имейте в виду, что приведенный выше код просто добавляет текст в конец текущего содержимого RTF; для реального использования вы, вероятно, захотите обработать случай, когда вы хотите, чтобы вставленный текст вставлялся в текущую точку вставки в RichTextBox (это очень легко сделать). Я протестировал код, чтобы убедиться, что ошибка не возникает, если буфер обмена пуст: проблем нет. - person BillW; 11.01.2010
comment
Я думаю о решении, направленном на постоянную фильтрацию содержимого. Если форматированный текст поступает в нечеловеческое время (т. е. вставляется), преобразуйте его в обычный текст. - person Aaron Anodide; 05.05.2012
comment
когда вы что-то выделили и нажали Ctrl+V, вы ожидаете, что старое выделение будет заменено содержимым буфера обмена, но в вашем решении оно добавлено. Кстати, двухстрочное решение @nQk отлично работает) - person luchaninov; 15.07.2012
comment
Небольшая поправка: postRTFContent на самом деле должен быть заполнен richTextBox2.Text.Substring(insPt + richTextBox2.SelectionLength), чтобы выделенный текст заменялся при вставке, как и должно быть. Кроме того, устаревшее сочетание клавиш Shift+Insert также должно быть добавлено в качестве комбинации клавиш. - person Nyerguds; 17.02.2016
comment
Кроме того, я обнаружил, что, несмотря на SuspendLayout(), изменение текста все равно обновит элемент управления. Лучший способ предотвратить это — внести как можно меньше изменений в свойство Text, сначала составив строку, а затем просто назначив ее один раз. - person Nyerguds; 17.02.2016

Добавьте обработчик к событию KeyDown, чтобы перехватывать стандартную вставку и вручную вставлять только обычный текст:

private void rtb_KeyDown(object sender, KeyEventArgs e)
{
    if (e.Control && e.KeyCode == Keys.V)
    {
        ((RichTextBox)sender).Paste(DataFormats.GetFormat("Text"));
            e.Handled = true;
    }
}
person nQk    schedule 23.01.2010
comment
Ох. Идеально. Однако также требует обработки Shift + Insert. - person Nyerguds; 17.02.2016

Я искал richtextbox только для открытого текста, но не нашел решения в Интернете.

Почему только открытый текст RichTextBox вместо TextBox? Например, потому что RichTextBox имеет полезные функции отмены/возврата и многое другое.

Наконец, я нашел идеальное решение, покопавшись в заголовочных файлах C элемента управления richedit: RichTextBox можно переключить в режим обычного текста, после чего он не принимает форматированный текст, изображения и подобные вещи из буфера обмена и ведет себя как обычный TextBox форматирование. Необычные вещи, такие как изображения, не могут быть вставлены, и он вставляет форматированный текст, удаляя форматирование.

class PlainRichTextBox : RichTextBox
{
    const int WM_USER = 0x400;
    const int EM_SETTEXTMODE = WM_USER + 89;
    const int EM_GETTEXTMODE = WM_USER + 90;

    // EM_SETTEXTMODE/EM_GETTEXTMODE flags
    const int TM_PLAINTEXT = 1;
    const int TM_RICHTEXT = 2;          // Default behavior 
    const int TM_SINGLELEVELUNDO = 4;
    const int TM_MULTILEVELUNDO = 8;    // Default behavior 
    const int TM_SINGLECODEPAGE = 16;
    const int TM_MULTICODEPAGE = 32;    // Default behavior 

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

    bool m_PlainTextMode;

    // If this property doesn't work for you from the designer for some reason
    // (for example framework version...) then set this property from outside
    // the designer then uncomment the Browsable and DesignerSerializationVisibility
    // attributes and set the Property from your component initializer code
    // that runs after the designer's code.
    [DefaultValue(false)]
    //[Browsable(false)]
    //[DesignerSerializationVisibility(DesignerSerializationVisibility.Hidden)]
    public bool PlainTextMode
    {
        get
        {
            return m_PlainTextMode;
        }
        set
        {
            m_PlainTextMode = value;
            if (IsHandleCreated)
            {
                IntPtr mode = value ? (IntPtr)TM_PLAINTEXT : (IntPtr)TM_RICHTEXT;
                SendMessage(Handle, EM_SETTEXTMODE, mode, IntPtr.Zero);
            }
        }
    }

    protected override void OnHandleCreated(EventArgs e)
    {
        // For some reason it worked for me only if I manipulated the created
        // handle before calling the base method.
        PlainTextMode = m_PlainTextMode;
        base.OnHandleCreated(e);
    }
}
person pasztorpisti    schedule 03.12.2013

Ответ от pasztorpisti сработал для меня как шарм. Поскольку я использую vb.net, я решил опубликовать свой переведенный код для других:

Imports System.Runtime.InteropServices
Imports System.ComponentModel

Public Class MyRichTextBox
    Inherits Windows.Forms.RichTextBox

    Public Const WM_USER As Integer = &H400
    Public Const EM_SETTEXTMODE As Integer = WM_USER + 89
    Public Const EM_GETTEXTMODE As Integer = WM_USER + 90

    'EM_SETTEXTMODE/EM_GETTEXTMODE flags
    Public Const TM_PLAINTEXT As Integer = 1
    Public Const TM_RICHTEXT As Integer = 2          ' Default behavior 
    Public Const TM_SINGLELEVELUNDO As Integer = 4
    Public Const TM_MULTILEVELUNDO As Integer = 8    ' Default behavior 
    Public Const TM_SINGLECODEPAGE As Integer = 16
    Public Const TM_MULTICODEPAGE As Integer = 32    ' Default behavior

    <DllImport("user32.dll", SetLastError:=True, CharSet:=CharSet.Auto)> _
    Private Shared Function SendMessage(ByVal hWnd As IntPtr, ByVal Msg As UInteger, ByVal wParam As IntPtr, ByVal lParam As IntPtr) As IntPtr
    End Function

    Private _plainTextMode As Boolean = False
    <DefaultValue(False),
      Browsable(True)>
    Public Property PlainTextMode As Boolean
        Get
            Return _plainTextMode
        End Get
        Set(value As Boolean)
            _plainTextMode = value

            If (Me.IsHandleCreated) Then
                Dim mode As IntPtr = If(value, TM_PLAINTEXT, TM_RICHTEXT)
                SendMessage(Handle, EM_SETTEXTMODE, mode, IntPtr.Zero)
            End If
        End Set
    End Property

    Protected Overrides Sub OnHandleCreated(e As EventArgs)
        'For some reason it worked for me only if I manipulated the created
        'handle before calling the base method.
        Me.PlainTextMode = _plainTextMode

        MyBase.OnHandleCreated(e)
    End Sub
End Class
person mike    schedule 10.09.2015

Что ж, RichTextBox имеет свойство SelectionFont, поэтому вы можете, например, сделать следующее:

Font courier;
courier = new Font("Courier new", 10f, FontStyle.Regular);
myRtb.SelectionFont = courier;
myRtb.Font = courier; //So the typed text is also the same font

Если текст будет вставлен, он будет автоматически отформатирован.

person Memet Olsen    schedule 06.11.2012

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

private void richTextBox1_KeyDown(object sender, KeyEventArgs e)
{
    if (e.Control && e.KeyCode == Keys.V)
    {
        richTextBox1.SelectedText = (string)Clipboard.GetData("Text");
        e.Handled = true;
    }
}
person Thirusanguraja Venkatesan    schedule 08.10.2013
comment
Рассмотрите возможность расширения своего ответа, чтобы объяснить спрашивающему, почему это приводит к желаемому результату, возможно, со ссылкой на документацию. Как есть, это лишь незначительно полезно. - person Joshua Dwire; 08.10.2013

Я добился этого, обновив шрифт и цвет для всего RTB при изменении его содержимого. Это отлично работает для меня, так как поле ввода не должно иметь дело с огромным количеством текста.

public FormMain()
{
    InitializeComponent();
    txtRtb.TextChanged += txtRtb_TextChanged;
}

void txtRtb_TextChanged(object sender, EventArgs e)
{
    RichTextBox rtb = (RichTextBox)sender;
    rtb.SelectAll();
    rtb.SelectionFont = rtb.Font;
    rtb.SelectionColor = System.Drawing.SystemColors.WindowText;
    rtb.Select(rtb.TextLength,0);
}
person deed02392    schedule 26.05.2015

Мое решение

private void OnCommandExecuting(object sender, Telerik.Windows.Documents.RichTextBoxCommands.CommandExecutingEventArgs e)
{
    if (e.Command is PasteCommand)
    {
        //override paste when clipboard comes from out of RichTextBox (plain text)
        var documentFromClipboard = ClipboardEx.GetDocumentFromClipboard("RadDocumentGUID");
        if (documentFromClipboard == null)
        {
            (sender as RichTextBox).Insert(Clipboard.GetText());
            e.Cancel = true;
        }
    }
}
person user11261094    schedule 26.03.2019

Есть очень простой способ сделать это, который хорошо работает для меня:

private bool updatingText;

public MyForm() {
    InitializeComponent();
    inputTextBox.TextChanged += inputTextBox_TextChanged;
}
private void inputTextBox_TextChanged(object sender, EventArgs e)
{
    if (updatingText)
    {
        return;
    }
    updatingText = true;
    try
    {
        var i = inputTextBox.SelectionStart;
        var text = inputTextBox.Text;
        inputTextBox.Rtf = "";
        inputTextBox.Text = text;
        inputTextBox.SelectionStart = i;
    }
    catch (Exception){}
    updatingText = false;
}

Поскольку свойство Text по своей сути не форматирует сброс текста RTF, установка свойства text на необработанный ввод удаляет любые специальные элементы, которые могли быть вставлены.

person cyborg    schedule 03.12.2019

Просто, но все в буфере обмена находится в виде обычного текста, когда приложение открыто.

private void timer2_Tick(object sender, EventArgs e)
        {
            string paste = Clipboard.GetText();
            Clipboard.SetText(paste);
        }
person Brokdel    schedule 08.12.2013