代码之家  ›  专栏  ›  技术社区  ›  Michal Czardybon

更改单个应用程序(Windows,.NET)的系统颜色

  •  5
  • Michal Czardybon  · 技术社区  · 17 年前

    我知道我通常应该避免弄乱这样的系统设置,但我的应用程序已经使用了非标准的颜色,我对此没有影响。我想能够添加一些地方的标准.NET控件,但它们的颜色不匹配。我想有一个黑客,将取代这个应用程序的系统颜色。需要注意的一点是,它是一个.NET应用程序。

    到目前为止,我的(不完整的)想法是:

    • 用替换的GetSysColor创建一个proxy User32.dll库,但这将非常繁琐(731个函数被重定向,1个被替换),我不知道如何强制我的应用程序使用该特定副本。
    • 以某种方式修改.NET类SystemColors(在内存中?有可能吗?)。

    你有什么想法,什么是最好的(和完整的)方法来实现这一点?

    3 回复  |  直到 16 年前
        1
  •  4
  •   Joel Coehoorn    17 年前

    我想能够添加一些地方的标准.NET控件,但它们的颜色不匹配。我想有一个黑客,将取代这个应用程序的系统颜色。

    就像用大锤钉钉子一样。

    与其在系统本身中弄脏颜色,不如 继承 ThemedTextBox 就继承结构而言,仍然是文本框您可以在任何使用普通文本框的地方使用它,包括在winforms设计器中。

        2
  •  2
  •   Thorsten Dittmar    17 年前

    在我早期的日子里,我开发了一个程序,注册了一个全局消息钩子来绘制窗口边框——我可以为所有窗口设置主题。这对于单个应用程序也是可能的。然而,这是 一项简单的任务。

    否则我认为这是不可能的。如何使用主题化的第三方控件,如 Krypton Toolkit ?

        3
  •  -1
  •   Nikolay Hidalgo Diaz    7 年前

    System.Drawing.SystemColor KnownColorsTable 在私有数组中初始化 colorTable . 使用Win32 API请求,在系统颜色更改时填充和更新数组的内容。

    可着色的

    然后您还需要清除 SystemBrushes SystemPens 类,因为钢笔和刷子不会自己重新读取RBG值。

    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);
    
                _threadDataProperty = systemDrawingAssembly.GetType("System.Drawing.SafeNativeMethods")
                    .GetNestedType("Gdip", BindingFlags.NonPublic)
                    .GetProperty("ThreadData", BindingFlags.Static | BindingFlags.NonPublic);
    
                SystemBrushesKey = typeof(SystemBrushes)
                    .GetField("SystemBrushesKey", BindingFlags.Static | BindingFlags.NonPublic)
                    .GetValue(null);
    
                SystemPensKey = typeof(SystemPens)
                    .GetField("SystemPensKey", BindingFlags.Static | BindingFlags.NonPublic)
                    .GetValue(null);
            }
    
            public void SetColor(KnownColor knownColor, Color value)
            {
                _colorTable[(int) knownColor] = value.ToArgb();
                ThreadData[SystemBrushesKey] = null;
                ThreadData[SystemPensKey] = null;
            }
    
            private int[] _colorTable;
            private object SystemBrushesKey { get; }
            private object SystemPensKey { get; }
        }
    }
    

    更完整的 example 我是如何为我的爱好项目做的。

    在加载应用程序之前,应该更改系统颜色,以确保控件在初始化时看到更改的值。您将需要使用win32api直接呈现控件本身的附加技巧,例如 ListView TreeView .

    here . 这是俄语的机器翻译。

    推荐文章