C# RichTextBox 移除自定义 SelectionBackColor
C# RichTextBox Remove Custom SelectionBackColor
经过一些研究,我相信我问的是与 Remove richtextbox SelectionBackColor 相同的问题。我遇到了同样的问题,但我认为该线程中的答案是不够的,因为问题没有得到清楚的解释。请看下面:
在 RichTextBox
中,我如何 删除 自定义 BackColor
来自一些但不是全部的文本 (SelectionBackColor
) 以便它假定控件 的 BackColor
,即使 BackColor
将来发生变化?
我有一种方法可以突出显示一些文本并使用 SelectionBackColor
更改其 BackColor
。我有另一种方法可以更改整个控件的 BackColor
。这些事件可以独立发生。
如果我想 "remove" 一些 SelectionBackColor
,我可以尝试将 SelectionBackColor
设置为 Color.Transparent
,但它最终变成了白色。如果我的 RichTextBox
的 current 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
对象中键入一些文本,突出显示其中的一小部分,然后使框失去焦点。您将看到以黄色突出显示的文本。然后,使框获得焦点。正如预期的那样,黄色背景将消失。但是,如果您将插入符号移到文本的其他位置并使控件再次失去焦点,您将看到先前突出显示的文本不再采用灰色背景颜色。
这很有趣。似乎(在我测试过的 Windows 7/.Net 3.5 上,也许在其他地方)System.Windows.Forms.RichTextBox.SelectionBackColor
may have a bug clearing the selection back color. The 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
. Nor does it clear the color when set to 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 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);
}
我做到了:
SelectionBackColor = default(Color);
而且效果很好。
经过一些研究,我相信我问的是与 Remove richtextbox SelectionBackColor 相同的问题。我遇到了同样的问题,但我认为该线程中的答案是不够的,因为问题没有得到清楚的解释。请看下面:
在 RichTextBox
中,我如何 删除 自定义 BackColor
来自一些但不是全部的文本 (SelectionBackColor
) 以便它假定控件 的 BackColor
,即使 BackColor
将来发生变化?
我有一种方法可以突出显示一些文本并使用 SelectionBackColor
更改其 BackColor
。我有另一种方法可以更改整个控件的 BackColor
。这些事件可以独立发生。
如果我想 "remove" 一些 SelectionBackColor
,我可以尝试将 SelectionBackColor
设置为 Color.Transparent
,但它最终变成了白色。如果我的 RichTextBox
的 current 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
对象中键入一些文本,突出显示其中的一小部分,然后使框失去焦点。您将看到以黄色突出显示的文本。然后,使框获得焦点。正如预期的那样,黄色背景将消失。但是,如果您将插入符号移到文本的其他位置并使控件再次失去焦点,您将看到先前突出显示的文本不再采用灰色背景颜色。
这很有趣。似乎(在我测试过的 Windows 7/.Net 3.5 上,也许在其他地方)System.Windows.Forms.RichTextBox.SelectionBackColor
may have a bug clearing the selection back color. The 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
. Nor does it clear the color when set to 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 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);
}
我做到了:
SelectionBackColor = default(Color);
而且效果很好。