C# RichTextBox 删除自定义 SelectionBackColor [英] C# RichTextBox Remove Custom SelectionBackColor

查看:55
本文介绍了C# RichTextBox 删除自定义 SelectionBackColor的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

在做了一些研究之后,我相信我在问与删除richtextbox SelectionBackColor相同的问题.我遇到了同样的问题,但我相信该线程中的答案是不够的,因为问题没有得到清楚的解释.请参阅以下内容:

After having done some research, I believe I am asking the same question as Remove richtextbox SelectionBackColor. I have encountered the same issue, but I believe the answers in that thread were insufficient as the question was not clearly explained. Please see below:

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

In a RichTextBox, how do I remove a custom BackColor from some, but not all, of the text (SelectionBackColor) so that it assumes the BackColor of the control even if that BackColor changes in the future?

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

I have a method that highlights some text and changes its BackColor using SelectionBackColor. I have another method that changes the BackColor of the entire control. These events can happen independently.

如果我想删除"一些SelectionBackColor,我可以尝试将SelectionBackColor 设置为Color.Transparent,但它最终白人.如果我的 RichTextBoxcurrent BackColor 是白色,那暂时没问题.如果我将 SelectionBackColor 设置为当前的 BackColor,暂时没问题,直到 BackColor 从另一个方法改变.

If I want to "remove" some SelectionBackColor, I can try to set the SelectionBackColor to Color.Transparent, but it ends up being White. That is fine, temporarily, if my RichTextBox's current BackColor is White. If I set SelectionBackColor to the current BackColor, it is fine temporarily, until that BackColor changes from another method.

RichTextBox.BackColor 更改后,之前突出显示的任何地方都使用白色或之前的 BackColor,而不是像以前没有的文本那样采用新颜色突出显示.

After the RichTextBox.BackColor has changed, any places that were previously highlighted use White or the previous BackColor, instead of assuming the new color like text that had not previously highlighted.

我已尝试删除和替换文本,但据我所知,这无法保留该文本的任何其他自定义格式.将 SelectionBackColor 设置为 null 不起作用.

I have tried deleting and replacing the text, but that negates the ability to retain any other custom formatting of that text, to my knowledge. Setting SelectionBackColor to null does not work.

使用下面的代码可以很容易地看到我在说什么:

One can easily see what I am talking about using the code below:

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 对象中,突出显示其中的一小部分,然后使框失去焦点.您将看到以黄色突出显示的文本.然后,使框获得焦点.正如预期的那样,黄色背景将消失.但是,如果您将插入符号移到文本中的其他位置并使控件再次失去焦点,您将看到之前突出显示的文本没有采用灰色背景色.

Type some text into a custom RichTextBox object with the code above, highlight a small portion of it, then make the box lose focus. You will see the highlighted text in yellow. Then, make the box gain focus. The yellow background will go away, as expected. However, if you move your caret elsewhere in the text and make the control lose focus again, you will see the previously-highlighted text does not assume the gray background color.

推荐答案

这很有趣.看来(在我测试过的 Windows 7/.Net 3.5 上,也许在其他地方)System.Windows.Forms.RichTextBox.SelectionBackColor 可能存在清除选择背景颜色的错误.源代码:

This is interesting. It appears that (on Windows 7/.Net 3.5 where I tested and perhaps elsewhere) System.Windows.Forms.RichTextBox.SelectionBackColor may have a bug clearing the selection back color. The source code does:

    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 时,源代码看起来好像试图清除选择背景颜色——但至少在我的机器上,它什么也不做.

This does not, as you have noticed, actually clear the back color when set to richTextBox.BackColor. Nor does it clear the color when set to RichTextBox.DefaultBackColor, which simply sets the selection back color to the default grey control color. It looks as though the source code is trying to clear the selection back color when set to Color.Empty -- but on my machine at least, it does nothing.

但如果我创建一个扩展方法,在发送消息之前也将 cf2.dwMask = RichTextBoxConstants.CFM_BACKCOLOR; 设置为空颜色,那么 SetSelectionBackColor(Color.Empty) 现在可以使用了!

But if I create an extension method that also sets cf2.dwMask = RichTextBoxConstants.CFM_BACKCOLOR; for an empty color before sending the message, then SetSelectionBackColor(Color.Empty) now works!

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

完整方法,常量和类改编自 此处这里这里此处这里:

Full method, with constants and classes adapted from here and here and here and here and 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);
}

这篇关于C# RichTextBox 删除自定义 SelectionBackColor的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆