2015-02-04 3 views
2

Проведя некоторые исследования, я считаю, что задаю тот же вопрос, что и Remove richtextbox SelectionBackColor. Я столкнулся с той же проблемой, но считаю, что ответы в этом потоке были недостаточными, поскольку вопрос не был четко объяснен. Пожалуйста, смотрите ниже:C# RichTextBox Удалить пользовательский SelectionBackColor

В RichTextBox, как я удалить обычай BackColor от некоторых, но не все, из текста (SelectionBackColor), так что он принимает BackColor элемента управления даже если что BackColor изменения будущее?

У меня есть метод, который выделяет текст и изменяет его BackColor с использованием SelectionBackColor. У меня есть другой метод, который изменяет BackColor всего элемента управления. Эти события могут происходить независимо.

Если я хочу «удалить» некоторые SelectionBackColor, я могу попытаться установить SelectionBackColor на Color.Transparent, но в итоге он становится белым. Это нормально, временно, если мой RichTextBoxтекущийBackColor Белый. Если я установил SelectionBackColor в текущий BackColor, штраф временно, до тех пор, пока BackColor не изменится с другого метода.

После RichTextBox.BackColor изменилось, все места, которые ранее были выделены белым и предыдущий BackColor, вместо того, чтобы принять на себя новый цвет, как текст, который ранее не выделен.

Я испробовал удаление и замену текста, но это, как мне известно, отрицает возможность сохранения любого другого настраиваемого форматирования этого текста. Установка SelectionBackColor в null не работает.

можно легко увидеть, что я имею в виду, используя код ниже:

protected override void OnLostFocus(EventArgs e) 
{ 
    base.OnLostFocus(e); 
    this.BackColor = Color.Gray; 
    if (SelectionLength > 0) 
    { 
     SelectionBackColor = Color.Yellow; 
    } 
} 

protected override void OnGotFocus(EventArgs e) 
{ 
    base.OnGotFocus(e); 
    this.ResetBackColor(); 
    if (SelectionLength > 0) 
    { 
     // The goal of this line is to "remove" the yellow. 
     // By assigning it any value, it seems to have lost 
     // the ability to use the control's BackColor normally. 
     SelectionBackColor = this.BackColor;// or Color.Transparent 
    } 
} 

Введите текст в обычае RichTextBox объект с кодом выше, выделить небольшую часть его, а затем сделать ящик потерять фокус. Вы увидите выделенный текст желтым цветом. Затем сделайте фокус усиления поля. Желтый фон исчезнет, ​​как и ожидалось. Однако, если вы переместите свой карет в другом месте текста и снова потеряете фокус, вы увидите, что ранее выделенный текст не предполагает серый цвет фона.

+0

Как о предоставлении какой-то код, чтобы работать на? –

+0

Я не могу использовать исходный код, как на другом заблокированном рабочем компьютере. См. Упрощенный пример, приведенный выше. – Matthew

+0

Я не думаю, что это возможно. Цвета - это значения текстовых фрагментов, а не ссылки в какое-то пространство. Поэтому вам нужно будет перебрать весь текст, чтобы изменить любые цвета. Вы можете заглянуть в код rtf, чтобы понять, что я имею в виду. (И прозрачность в любом случае не является реальным цветом, поэтому здесь это тоже не поможет.) – TaW

ответ

2

Это интересно. Похоже, что (в Windows 7/.Net 3.5, где я тестировал и, возможно, в другом месте) System.Windows.Forms.RichTextBox.SelectionBackColor может иметь ошибку, очищающую цвет выделения. source code делает:

public Color SelectionBackColor { 
     set 
     { 
      //Note: don't compare the value to the old value here: it's possible that 
      //you have a different range selected. 
      selectionBackColorToSetOnHandleCreated = value; 
      if (IsHandleCreated) 
      { 
       NativeMethods.CHARFORMAT2A cf2 = new NativeMethods.CHARFORMAT2A(); 
       if (value == Color.Empty) 
       { 
        cf2.dwEffects = RichTextBoxConstants.CFE_AUTOBACKCOLOR; 
       } 
       else 
       { 
        cf2.dwMask = RichTextBoxConstants.CFM_BACKCOLOR; 
        cf2.crBackColor = ColorTranslator.ToWin32(value); 
       } 

       UnsafeNativeMethods.SendMessage(new HandleRef(this, Handle), RichTextBoxConstants.EM_SETCHARFORMAT, RichTextBoxConstants.SCF_SELECTION, cf2); 
      } 
     } 
    } 

Это не, как вы заметили, на самом деле очистить задний цвет, когда установлен richTextBox.BackColor. Также он не очищает цвет, если он установлен на RichTextBox.DefaultBackColor, который просто устанавливает цвет выделения на серый цвет управления по умолчанию. Похоже, что исходный код пытается до очистить цвет выделения, если он установлен на Color.Empty, - но на моей машине, по крайней мере, ничего не делает.

Но если я создаю метод расширения, который также устанавливает cf2.dwMask = RichTextBoxConstants.CFM_BACKCOLOR; для пустого цвета перед отправкой сообщения, тогда SetSelectionBackColor(Color.Empty) теперь работает!

public static void SetSelectionBackColor(this RichTextBox richTextBox, Color value) 
    { 
     if (richTextBox.IsHandleCreated && value == Color.Empty) 
     { 
      var cf2 = new CHARFORMAT2(); 

      cf2.dwEffects = RichTextBoxConstants.CFE_AUTOBACKCOLOR; 
      cf2.dwMask = RichTextBoxConstants.CFM_BACKCOLOR; 
      cf2.crBackColor = ColorTranslator.ToWin32(value); 

      UnsafeNativeMethods.SendMessage(new HandleRef(richTextBox, richTextBox.Handle), RichTextBoxConstants.EM_SETCHARFORMAT, RichTextBoxConstants.SCF_SELECTION, cf2); 
     } 
     else 
     { 
      richTextBox.SelectionBackColor = value; 
     } 
    } 

Полный метод, с константами и классами адаптировано из here и here и here и here и here:

public static class RichTextBoxConstants 
{ 
    // http://referencesource.microsoft.com/#System.Windows.Forms/winforms/Managed/System/WinForms/RichTextBoxConstants.cs,31b52ac41e96a888 
    /* EM_SETCHARFORMAT wparam masks */ 
    internal const int SCF_SELECTION = 0x0001; 

    internal const int EM_SETCHARFORMAT = (NativeMethods.WM_USER + 68); 

    internal const int CFM_BACKCOLOR = 0x04000000; 

    /* NOTE: CFE_AUTOCOLOR and CFE_AUTOBACKCOLOR correspond to CFM_COLOR and 
     CFM_BACKCOLOR, respectively, which control them */ 
    internal const int CFE_AUTOBACKCOLOR = CFM_BACKCOLOR; 
} 

[StructLayout(LayoutKind.Sequential, Pack = 4)] 
public class CHARFORMAT2 
{ 
    // http://referencesource.microsoft.com/#System.Windows.Forms/winforms/Managed/System/WinForms/NativeMethods.cs,acde044a28b57a48 
    // http://pinvoke.net/default.aspx/Structures/CHARFORMAT2.html 

    public int cbSize = Marshal.SizeOf(typeof(CHARFORMAT2)); 
    public int dwMask; 
    public int dwEffects; 
    public int yHeight; 
    public int yOffset; 
    public int crTextColor; 
    public byte bCharSet; 
    public byte bPitchAndFamily; 
    [MarshalAs(UnmanagedType.ByValTStr, SizeConst = 32)] 
    public string szFaceName; 
    public short wWeight; 
    public short sSpacing; 
    public int crBackColor; 
    public int lcid; 
    public int dwReserved; 
    public short sStyle; 
    public short wKerning; 
    public byte bUnderlineType; 
    public byte bAnimation; 
    public byte bRevAuthor; 
    public byte bReserved1; 
} 

public static class NativeMethods 
{ 
    // http://referencesource.microsoft.com/#System.Windows.Forms/winforms/Managed/System/WinForms/NativeMethods.cs,e75041b5218ff60b 

    public const int WM_USER = 0x0400; 

    public static void SetSelectionBackColor(this RichTextBox richTextBox, Color value) 
    { 
     if (richTextBox.IsHandleCreated && value == Color.Empty) 
     { 
      var cf2 = new CHARFORMAT2(); 

      cf2.dwEffects = RichTextBoxConstants.CFE_AUTOBACKCOLOR; 
      cf2.dwMask = RichTextBoxConstants.CFM_BACKCOLOR; 
      cf2.crBackColor = ColorTranslator.ToWin32(value); 

      UnsafeNativeMethods.SendMessage(new HandleRef(richTextBox, richTextBox.Handle), RichTextBoxConstants.EM_SETCHARFORMAT, RichTextBoxConstants.SCF_SELECTION, cf2); 
     } 
     else 
     { 
      richTextBox.SelectionBackColor = value; 
     } 
    } 
} 

public static class UnsafeNativeMethods 
{ 
    // http://referencesource.microsoft.com/#System.Windows.Forms/winforms/Managed/System/WinForms/UnsafeNativeMethods.cs,0d546f58103867e3 
    // For RichTextBox 
    // 
    [DllImport("user32.dll", CharSet = CharSet.Auto)] 
    public static extern IntPtr SendMessage(HandleRef hWnd, int msg, int wParam, [In, Out, MarshalAs(UnmanagedType.LPStruct)] CHARFORMAT2 lParam); 
} 
+0

Я не упомянул, что попробовал Color.Empty. Я использую .NET 4.0 на компьютере XP (помните, компьютер с закрытой записью), а Color.Empty указывает на белый. Мы переходим на Windows 8, и у меня может быть доступ к .NET 4.5. Надеюсь, этот вопрос проще решить после миграции. Спасибо за вашу тяжелую работу. Я увижу, как интегрировать это как решение, пока я все еще нахожусь на XP, предполагая, что могу получить все это без подрывной политики компании. – Matthew

+0

@Matthew - Я подозреваю, что ошибка существует и на Win8/.Net 4.5, и мое исправление работает там, так как [источник ссылки] (http://referencesource.microsoft.com/#System.Windows.Forms/ winforms/Managed/System/WinForms/RichTextBox.cs, d0f4a24face1b591) соответствует самой последней версии .Net и Windows. Не на 100% уверен, что он будет работать на XP, но он мог бы попробовать. – dbc

+0

@Matthew - Я скопировал константы в блоке из исходного источника и pinvoke.net. Вероятно, вы могли бы сократить до 5 или 6 констант, если вам нужно это сделать. – dbc

Смежные вопросы