Изменение системных цветов для одного приложения (Windows, .NET)

Я знаю, что, как правило, следует избегать путаницы с такими настройками системы, но в моем приложении уже используются нестандартные цвета, и я не имею на это никакого влияния. Я хотел бы иметь возможность добавлять стандартные элементы управления.NET в некоторых местах, но их цвета не совпадают. Я хотел бы иметь хак, который заменит системные цвета для этого одного приложения. Еще одна важная вещь, которую стоит отметить, - это приложение.NET.

Мои (неполные) идеи до сих пор были:

  • Создать прокси-библиотеку User32.dll с замененным GetSysColor, но это было бы очень утомительно (731 функция должна быть перенаправлена, 1 заменена), и я не знаю, как заставить мое приложение использовать эту конкретную копию.
  • Чтобы как-то перехватить вызовы GetSysColors (к сожалению, это где-то в CLR, я думаю).
  • Модифицировать как-то.NET класс SystemColors (в памяти "возможно ли").

Есть ли у вас какие-либо идеи, каков наилучший (и полный) способ достижения этого?

3 ответа

Я хотел бы иметь возможность добавлять стандартные элементы управления.NET в некоторых местах, но их цвета не совпадают. Я хотел бы иметь хак, который заменит системные цвета для этого одного приложения.

Это похоже на вбивание гвоздя кувалдой.

Вместо того чтобы смешивать цвета в самой системе, вы можете унаследовать новый элемент управления от каждого элемента управления запасами, который вы хотите использовать. Таким образом, вместо простого TextBox вы наследуете от стандартного элемента управления TextBox, чтобы создать свой собственный ThemedTextBox, Вы устанавливаете этот новый элемент управления для использования цветовой схемы вашего приложения по умолчанию, и, поскольку это все еще TextBox, что касается структуры наследования, вы можете использовать его везде, где вы будете использовать обычное текстовое поле, в том числе в конструкторе winforms.

В ранние годы я разработал программу, которая регистрировала глобальный хук сообщений для границ окна рисования владельца - я мог оформлять темы для всех окон. Это должно быть возможно и для одного приложения. Однако это не простая задача.

В противном случае я не думаю, что это будет возможно. Как насчет использования настраиваемых сторонних элементов управления, таких как Krypton Toolkit?

System.Drawing.SystemColor значения кэшируются в KnownColorsTable класс в приватном массиве colorTable, Содержимое массива заполняется и обновляется по мере изменения системных цветов с помощью запросов Win32 API.

Чтобы изменить системные цвета в области применения, измените значения цвета, хранящиеся в colorTable ценностями, которые вы хотите.

using System.Drawing;
using System.Reflection;

namespace Example
{
    public class SystemColorsUtility
    {
        public SystemColorsUtility()
        {
            // force init color table
            byte unused = SystemColors.Window.R;

            var colorTableField = typeof(Color).Assembly.GetType("System.Drawing.KnownColorTable")
                .GetField("colorTable", BindingFlags.Static | BindingFlags.NonPublic);

            _colorTable = (int[]) colorTableField.GetValue(null);
        }

        public void SetColor(KnownColor knownColor, Color value)
        {
            _colorTable[(int) knownColor] = value.ToArgb();
        }

        private int[] _colorTable;
    }
}

Более полный пример того, как я это сделал для своего хобби-проекта.

Системные цвета должны быть изменены до загрузки приложения, чтобы гарантировать, что элементы управления увидят измененные значения при инициализации. Вам понадобятся дополнительные приемы с элементами управления, использующими Win32 API напрямую для рендеринга, такие как ListView или же TreeView,

Вы можете прочитать подробности об этом здесь. Это машинный перевод с русского.

Другие вопросы по тегам