Winforms ToolStrip.BackColor возвращает неправильный цвет

Источник моей проблемы

Я создал очень простое фиктивное приложение на 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();
}

Результатом является белый трекбар на светло-сером ToolStrip. Так кажется что

this.toolStrip.BackColor

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

Тем не мение...

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

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

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

Итак, вопрос в том ...

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

Это намеренное поведение или я что-то упускаю?


person churill    schedule 14.06.2019    source источник
comment
Элемент управления ToolStrip наследует свое свойство BackColor от родительской формы, но не устанавливает его, если вы не установите его вручную, сохраняя нейтральный цвет по умолчанию (белый, должен быть Color.FromArgb(248, 248, 248)). Итак, когда вы добавляете TrackBar, он наследует ToolStrip BackColor, равный BackColor формы, но вместо этого устанавливает его. Итак, если вы хотите разместить полупрозрачный элемент управления alien, установите BackColor TooStrip перед размещением элемента управления или установите BackColor элемента управления на фактический цвет ToolStrip.   -  person Jimi    schedule 14.06.2019


Ответы (1)


BackColor - это внешнее свойство

_1 _ - это окружающее свойство:

Свойство BackColor является внешним свойством. Окружающее свойство - это свойство элемента управления, которое, если не установлено, извлекается из родительского элемента управления. Например, кнопка по умолчанию будет иметь тот же цвет BackColor, что и ее родительская форма. Для получения дополнительных сведений об окружающих свойствах см. Класс AmbientProperties или обзор класса Control.

Значит, реализовано это так (источник):

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 имеет _ 8_, и инициализация этого средства визуализации зависит от настроек системы. Итак, в общем, нет простого способа получить задний цвет панели инструментов.

Скорее всего, по умолчанию ToolstripProfessionalRenderer. Этот тип рендерера фактически рисует фон градиентом. У него есть ColorTable , которое, в свою очередь, определяет _ 11_ и _ 12_.

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

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

Если вы попытаетесь разместить элемент управления с равномерно окрашенным фоном, например TrackBar, он, вероятно, будет выделяться на панели инструментов с градиентной заливкой.

ToolStripRenderer учитывает явно заданный цвет

Я нигде не мог найти это поведение, задокументированное, но согласно _ 15_ 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 полосы прокрутки и залейте ее градиентом, чтобы он сливался с фоном полосы инструментов. Звучит проблематично, но выполнимо.

person default locale    schedule 14.06.2019
comment
Спасибо за ответ. Во фреймворке творится что-то безумное. Я решил написать собственный метод рисования для трекбара, чтобы сохранить градиент на панели инструментов и нарисовать заднюю часть трекбара одним и тем же градиентом. - person churill; 14.06.2019