Winforms ToolStrip.BackColor返回错误的颜色

时间:2019-06-14 08:32:16

标签: c# winforms colors toolstrip

我的问题的根源

我使用Winforms在C#中创建了一个非常简单的虚拟应用程序。它在该ToolStrip中仅包含一个ToolStrip和一个TrackBar。 TrackBar应该具有与ToolStrip相同的BackColor,但似乎ToolStrip.BackColor属性不会返回实际的背景颜色。

public Form1()
{
    //// Here the ToolStrip is created.
    //// This code is generated by the designer.
    this.InitializeComponent();
    //// Here the the TrackBar is created.
    //// I think this is impossible to do via the Designer.
    this.CreateSpeedSlider();
}

private void CreateSpeedSlider()
{
    this.toolStrip.SuspendLayout();
    this.speedSlider = new TrackBar
    {
        TickStyle = TickStyle.None,
        AutoSize = false,
        Height = this.toolStrip.Height,
        Minimum = 0,
        Maximum = 10,
        BackColor = this.toolStrip.BackColor,
    };

    this.toolStrip.Items.Add(new ToolStripControlHost(this.speedSlider));
    this.toolStrip.ResumeLayout();
}

结果是浅灰色ToolStrip上的白色TrackBar。看来

this.toolStrip.BackColor

不返回实际用于绘制它的ToolStrip的背景颜色。

但是...

如果我将功能更改为

private void CreateSpeedSlider()
{
    this.toolStrip.BackColor = this.toolStrip.BackColor;
    ...
}

我在白色ToolStrip上看到一个白色滑块。所以...将属性的值分配给它本身实际上将颜色从浅灰色更改为白色?

所以问题是...

有没有一种好的方法来检索没有这种“ hacks”的ToolStrip的正确背景颜色?

这种行为是故意的还是我错过了什么?

1 个答案:

答案 0 :(得分:1)

BackColor是环境属性

Control.BackColor是环境属性:

  

BackColor属性是一个环境属性。环境属性是控件属性,如果未设置,则从父控件中检索它。例如,默认情况下,一个Button与其父Form具有相同的BackColor。有关环境属性的更多信息,请参见AmbientProperties类或Control类概述。

这意味着它的实现方式如下(source):

public virtual Color BackColor
{
     get
     {
          Color c = RawBackColor; // inheritedProperties.BackColor
          if (!c.IsEmpty)
          {
               return c;
          }
          Control p = ParentInternal;
          if (p != null && p.CanAccessProperties)
          {
               c = p.BackColor;
               if (IsValidBackColor(c))
               {
                    return c;
               }
          }
          ...

有一个内部属性RawBackColor,它是为此特定控件明确设置的颜色。 BackColor本身是经过计算的-如果未为此控件显式设置颜色,它将尝试返回其父级的BackColor

ToolStrip的呈现方式有所不同。

要为菜单实现不同的样式ToolStrip支持可配置的rendering

  

ToolStrip类实现的呈现方案与其他Windows Forms控件明显不同。使用此方案,您可以轻松应用样式和主题。

这意味着ToolStrip有一个Renderer,并且渲染器的初始化取决于系统设置。因此,通常没有简单的方法来获得工具条的背景色。

在默认情况下使用ToolstripProfessionalRenderer的可能性很好。这种类型的渲染器实际上是用渐变绘制背景。它具有ColorTable属性,该属性又定义了MenuStripGradientBeginMenuStripGradientEnd

因此,在大多数(但不是全部)情况下,您可以通过以下方式确定工具提示的默认背景色:

var renderer = (ToolStripProfessionalRenderer)toolStrip.Renderer;
Console.WriteLine(renderer.ColorTable.MenuStripGradientBegin);
Console.WriteLine(renderer.ColorTable.MenuStripGradientEnd);

如果您尝试托管具有统一绘制背景的控件(例如TrackBar),则该控件可能会在渐变填充的工具栏中突出显示。

ToolStripRenderer明确考虑了设置的颜色

我在任何地方都找不到这种行为的记录,但是根据ToolStripRenderer source,只有在未设置工具栏的RawBackColor的情况下,才会绘制背景(填充渐变):

internal bool ShouldPaintBackground(Control control)
{
    return (control.RawBackColor == Color.Empty && control.BackgroundImage == null);
}

因此,如果您将ToolStrip.BackColor显式设置为任何颜色,则渲染器将仅使用该颜色作为底色。这种令人困惑的行为解释了原因:

toolStrip.BackColor = toolStrip.BackColor;

有实际效果。

现在该怎么办?

我可以看到多种前进方式,但都不好:

  1. 将工具条和轨迹栏的BackColor设置为某种已知的颜色。这将杀死工具栏背景中的美丽渐变。如果您不太在意渐变,那是最简单的方法。

  2. 使托管控件透明,这样工具条的背景就会显示出来。由于某些原因,它不支持透明背景,因此不适用于TrackBar。请参阅此问题,以获取可能的选项(我没有尝试过):Trackbar Background in a TabControl

  3. 覆盖轨迹栏的OnPaint并用渐变填充,使其与工具条的背景融合。这听起来有问题,但可行。