C#RichTextBox删除Custom SelectionBackColor

时间:2015-02-04 17:01:22

标签: c# winforms richtextbox backcolor

在做了一些研究后,我相信我问的问题与Remove richtextbox SelectionBackColor相同。我遇到了同样的问题,但我认为该问题的答案不充分,因为问题没有得到明确解释。请参阅以下内容:

RichTextBox中,我如何从某些(但不是全部)文本(BackColor)中删除自定义SelectionBackColor,以便它假设控件<{>>的BackColor,即使BackColor将来发生变化?

我有一种方法可突出显示某些文字,并使用BackColor更改其SelectionBackColor。我有另一种方法可以更改整个控件的BackColor。这些事件可以独立发生。

如果我想&#34;删除&#34;一些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对象中键入一些文本,突出显示其中的一小部分,然后使框失去焦点。您将看到黄色突出显示的文本。然后,让盒子获得焦点。正如预期的那样,黄色背景将消失。但是,如果您将插入符号移动到文本的其他位置并使控件再次失去焦点,您将看到先前突出显示的文本不呈现灰色背景颜色。

2 个答案:

答案 0 :(得分: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时,它也不会清除颜色,here只是将选择颜色设置为默认的灰色控制颜色。看起来源代码尝试在设置为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;
        }
    }

完整方法,常量和类改编自herehere以及herehere以及{{3}}:

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);
}

答案 1 :(得分:0)

我做了:

SelectionBackColor = default(Color);

它工作正常。