Winforms ToolStrip.BackColor возвращает неправильный цвет - PullRequest
1 голос
/ 14 июня 2019

Происхождение моей проблемы

Я создал очень простое фиктивное приложение на C #, используя winforms. Он содержит только ToolStrip и TrackBar внутри этой ToolStrip. TrackBar должен иметь тот же BackColor, что и ToolStrip, но кажется, что свойство 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();
}

В результате получается белый трекбар на светло-серой панели инструментов. Похоже, что

this.toolStrip.BackColor

не возвращает задний цвет ToolStrip, который фактически используется для его рисования.

Однако ...

Если я изменю свою функцию на

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

Я получаю белый ползунок на белой панели инструментов. Итак ... присвоение значения свойства самому себе фактически меняет цвет с светло-серого на белый ???

Так что вопрос ...

Есть ли какой-нибудь хороший способ получить правильный цвет фона ToolStrip без таких «хаков»?

И это поведение преднамеренное или я что-то упустил?

1 Ответ

1 голос
/ 14 июня 2019

BackColor является свойством ambient

Control.BackColor является свойством ambient:

Свойство BackColor является свойством ambient.Свойство ambient - это свойство элемента управления, которое, если оно не установлено, извлекается из родительского элемента управления.Например, кнопка по умолчанию будет иметь тот же 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 поддерживает настраиваемый рендеринг :

Классы ToolStrip реализуют схему рендеринга, которая значительно отличается от других элементов управления Windows Forms.С помощью этой схемы вы можете легко применять стили и темы.

Это означает, что ToolStrip имеет Renderer и инициализация рендерера зависит от настроек системы.Таким образом, в общем случае нет простого способа получить задний цвет полосы инструментов.

Коэффициенты хороши, если по умолчанию используется ToolstripProfessionalRenderer.Этот тип рендера на самом деле рисует фон с градиентом.Он имеет свойство ColorTable, которое, в свою очередь, определяет MenuStripGradientBegin и MenuStripGradientEnd.

Таким образом, в большинстве(но не во всех) случаях вы можете определить задний цвет по умолчанию для всплывающей подсказки следующим образом:

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, так как по какой-то причине не поддерживает прозрачный фон.См. Этот вопрос для возможных вариантов (я не пробовал ни одного из них): Фон панели треков в TabControl .

  3. Переопределить панель треков OnPaint и заполнитеэто с градиентом, так что он сливается с фоном полосы инструмента.Это звучит проблематично, но выполнимо.

...