C# Visual Studio颜色特性编辑器中的自定义调色板

C# Visual Studio颜色特性编辑器中的自定义调色板,c#,.net,winforms,visual-studio,windows-forms-designer,C#,.net,Winforms,Visual Studio,Windows Forms Designer,在Visual Studio Designer中,在“属性”窗口下,可以使用颜色选择器选择前景色、背景色等。当你想要选择一种颜色时,一个颜色选择器会弹出“Custom,Web,System”选项卡。 如果选择“自定义”,则可以向选择器添加新颜色,但只有底部的两行是可更改的,并且更改不会在控件之间持续。因此,如果您向调色板添加颜色,当您选择另一个控件并希望更改例如BackColor时,您先前添加的颜色不存在 是否有方法创建自定义颜色集并将其导入设计器的颜色选择器控件 注意:这个问题不是问VS主题,

在Visual Studio Designer中,在“属性”窗口下,可以使用颜色选择器选择
前景色
背景色
等。当你想要选择一种颜色时,一个颜色选择器会弹出“Custom,Web,System”选项卡。 如果选择“自定义”,则可以向选择器添加新颜色,但只有底部的两行是可更改的,并且更改不会在控件之间持续。因此,如果您向调色板添加颜色,当您选择另一个控件并希望更改例如
BackColor
时,您先前添加的颜色不存在

是否有方法创建自定义颜色集并将其导入设计器的颜色选择器控件


注意:这个问题不是问VS主题,也不是问颜色是否可以在代码隐藏中实现为一个类。我正在寻找一种定制设计器的方法。

帮助您在visual studio中选择颜色的编辑器是,它不会在不同控件之间持久化自定义颜色。要解决此问题,您应该:

  • 基于
    ColorEditor
  • 在visual studio启动时为类型
    Color
    注册编辑器
下面是一个详细的答案,包括我用来解决这个问题的代码

创建CustomColorEditor

class CustomColorEditor : ColorEditor
{
    private static Color[] Colors;
    static CustomColorEditor()
    {
        Colors = new Color[]{
            Color.Red, Color.Green, Color.Blue, Color.White, 
            Color.White, Color.White, Color.White, Color.White, 
            Color.White, Color.White, Color.White, Color.White, 
            Color.White, Color.White, Color.White, Color.White, 
        };
    }
    public override object EditValue(ITypeDescriptorContext context, System.IServiceProvider provider, object value)
    {
        var colorEditorObject = this;
        Type colorUiType = typeof(ColorEditor).GetNestedType("ColorUI", BindingFlags.NonPublic);
        var colorUiConstructor = colorUiType.GetConstructors()[0];
        var colorUiField = typeof(ColorEditor).GetField("colorUI", BindingFlags.Instance | BindingFlags.NonPublic);
        var colorUiObject = colorUiConstructor.Invoke(new[] { colorEditorObject });
        colorUiField.SetValue(colorEditorObject, colorUiObject);
        var palField = colorUiObject.GetType().GetField("pal", BindingFlags.Instance | BindingFlags.NonPublic);
        var palObject = palField.GetValue(colorUiObject);
        var palCustomColorsField = palObject.GetType().GetField("customColors", BindingFlags.Instance | BindingFlags.NonPublic);
        palCustomColorsField.SetValue(palObject, Colors);
        var selectedValue = base.EditValue(context, provider, value);
        Colors = palCustomColorsField.GetValue(palObject) as Color[];
        return selectedValue;
    }
}
ColorEditor
使用私有的
ColorUI
类来显示私有的
colorplate
控件。调色板使用一组颜色来显示自定义颜色

要创建
customcolordeditor
I派生自
colordeditor
并使用反射,找到这些成员并使用一些颜色的静态数组填充数组,以便在首次加载时显示。然后在关闭编辑器后,我从编辑器中获取自定义颜色,并将它们放入静态数组中,然后在下一次加载时使用此静态数组初始化颜色编辑器。这样,自定义颜色在my
CustomColorEditor
的所有实例之间共享

显示CustomColorEditor而不是默认ColorEditor

class CustomColorEditor : ColorEditor
{
    private static Color[] Colors;
    static CustomColorEditor()
    {
        Colors = new Color[]{
            Color.Red, Color.Green, Color.Blue, Color.White, 
            Color.White, Color.White, Color.White, Color.White, 
            Color.White, Color.White, Color.White, Color.White, 
            Color.White, Color.White, Color.White, Color.White, 
        };
    }
    public override object EditValue(ITypeDescriptorContext context, System.IServiceProvider provider, object value)
    {
        var colorEditorObject = this;
        Type colorUiType = typeof(ColorEditor).GetNestedType("ColorUI", BindingFlags.NonPublic);
        var colorUiConstructor = colorUiType.GetConstructors()[0];
        var colorUiField = typeof(ColorEditor).GetField("colorUI", BindingFlags.Instance | BindingFlags.NonPublic);
        var colorUiObject = colorUiConstructor.Invoke(new[] { colorEditorObject });
        colorUiField.SetValue(colorEditorObject, colorUiObject);
        var palField = colorUiObject.GetType().GetField("pal", BindingFlags.Instance | BindingFlags.NonPublic);
        var palObject = palField.GetValue(colorUiObject);
        var palCustomColorsField = palObject.GetType().GetField("customColors", BindingFlags.Instance | BindingFlags.NonPublic);
        palCustomColorsField.SetValue(palObject, Colors);
        var selectedValue = base.EditValue(context, provider, value);
        Colors = palCustomColorsField.GetValue(palObject) as Color[];
        return selectedValue;
    }
}
要为特定类型的所有属性显示ui类型编辑器,应向该类型添加属性。但是既然
Color
不是我的类型,我怎么能给它添加
Editor
属性呢

帮助我注册
Color
type的编辑器

我应该在哪里运行代码来注册属性?当然是在VisualStudio运行时

为此,我创建了一个VisualStudio包项目,并将注册代码放在包的
Initialize
方法中。我还向package类添加了属性,使其在打开解决方案时自动加载

然后我安装了软件包

然后,我使用
gacutil.exe/I“dll路径”
将dll放入GAC中。代替GAC,还可以将dll放在Visual Studio中的
devenv.exe
附近,因为Visual stusio运行时将使用它显示所有颜色属性的自定义颜色编辑器

结论

执行上述任务后,我打开了一个新的VisualStudio实例,在我的Windows窗体项目中,我看到我的自定义颜色编辑器显示为颜色。显示我设置的初始颜色。此外,即使在不同的表单之间,颜色编辑器也会保留自定义颜色

我在这里分享代码。您可以使用这些想法和代码来增强编辑器。您可以提供自定义颜色,以便在开始时在编辑器中显示。您甚至可以向编辑器添加另一个选项卡。这是我的密码:

颜色编辑器的代码

class CustomColorEditor : ColorEditor
{
    private static Color[] Colors;
    static CustomColorEditor()
    {
        Colors = new Color[]{
            Color.Red, Color.Green, Color.Blue, Color.White, 
            Color.White, Color.White, Color.White, Color.White, 
            Color.White, Color.White, Color.White, Color.White, 
            Color.White, Color.White, Color.White, Color.White, 
        };
    }
    public override object EditValue(ITypeDescriptorContext context, System.IServiceProvider provider, object value)
    {
        var colorEditorObject = this;
        Type colorUiType = typeof(ColorEditor).GetNestedType("ColorUI", BindingFlags.NonPublic);
        var colorUiConstructor = colorUiType.GetConstructors()[0];
        var colorUiField = typeof(ColorEditor).GetField("colorUI", BindingFlags.Instance | BindingFlags.NonPublic);
        var colorUiObject = colorUiConstructor.Invoke(new[] { colorEditorObject });
        colorUiField.SetValue(colorEditorObject, colorUiObject);
        var palField = colorUiObject.GetType().GetField("pal", BindingFlags.Instance | BindingFlags.NonPublic);
        var palObject = palField.GetValue(colorUiObject);
        var palCustomColorsField = palObject.GetType().GetField("customColors", BindingFlags.Instance | BindingFlags.NonPublic);
        palCustomColorsField.SetValue(palObject, Colors);
        var selectedValue = base.EditValue(context, provider, value);
        Colors = palCustomColorsField.GetValue(palObject) as Color[];
        return selectedValue;
    }
}
程序包代码

[PackageRegistration(UseManagedResourcesOnly = true)]
[InstalledProductRegistration("#110", "#112", "1.0", IconResourceID = 400)]
[Guid(GuidList.guidVSPackage1PkgString)]
[ProvideAutoLoad(Microsoft.VisualStudio.Shell.Interop.UIContextGuids80.SolutionExists)]
public sealed class VSPackage1Package : Package
{
    public VSPackage1Package() { }
    protected override void Initialize()
    {
        base.Initialize();
        TypeDescriptor.AddAttributes(typeof(Color), new EditorAttribute(typeof(CustomColorEditor), typeof(UITypeEditor)));
    }
}
结果

这将是Visual Studio属性窗口中的结果。查看对话框底部的
红色
绿色
蓝色
,我们添加了:


我知道已经有一段时间了

您可以使用合并词典并在App.xml文件中引用资源词典

这将把您定义的颜色放在调色板中,但您必须在每个App.xaml中包含相同的资源字典,并在您使用的每个应用程序中引用它。在我看来,这很好,因为有时您必须为不同的应用程序使用自定义颜色


类似这样的内容

编写一个代码,在“颜色”对话框中显示颜色属性