Home > Back-end >  How can I override ColorUI class of ColorEditor class and add a new Tab with custom colors?
How can I override ColorUI class of ColorEditor class and add a new Tab with custom colors?

Time:12-14

What I am trying to do is to add a custom tab with custom colors into the ColorUI class of enter image description here

I understand that in some way I have to create my own ColorEditor class and override the ColorUI class which is nested inside original ColorEditor class but I don't know which Method I have to override so to add this extra Tab etc.

Any idea?

CodePudding user response:

Probably a more flexible (and less hacky) solution will be recreating the ColorEditor as mentioned by Jimi. I also may take a totally different approach for supporting theme colors, for example creating a theme extender provider component, or creating derived controls or other possible solutions.

Anyways, to support my enter image description here

It's a real screenshot ;) not exactly what you asked, but good enough as a sample code. For example if you need to use custom names for the colors, then you need more customization in DrawItem (like what I did in the example), or rewriting the control from scratch.

And here's the code:

using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Drawing;
using System.Drawing.Design;
using System.Linq;
using System.Reflection;
using System.Windows.Forms;
public class CustomColorEditor : ColorEditor
{
    public override object EditValue(ITypeDescriptorContext
        context, System.IServiceProvider provider, object value)
    {
        //Get required types and methods
        var ColorUIType = typeof(ColorEditor).GetNestedType("ColorUI",
            BindingFlags.NonPublic | BindingFlags.Instance);
        var ColorUiConstructor = ColorUIType.GetConstructors()[0];
        var ColorEditorListBoxType = ColorUIType.GetNestedType("ColorEditorListBox",
            BindingFlags.NonPublic | BindingFlags.Instance);
        var ColorUiField = typeof(ColorEditor).GetField("colorUI",
            BindingFlags.NonPublic | BindingFlags.Instance);
        var OnListClickMethod = ColorUIType.GetMethod("OnListClick",
            BindingFlags.NonPublic | BindingFlags.Instance);
        var OnListDrawItemMethod = ColorUIType.GetMethod("OnListDrawItem",
            BindingFlags.NonPublic | BindingFlags.Instance);
        var OnListKeyDownMethod = ColorUIType.GetMethod("OnListKeyDown",
            BindingFlags.NonPublic | BindingFlags.Instance);

        //Color UI Control
        var colorUi = (Control)ColorUiConstructor.Invoke(new[] { this });
        ColorUiField.SetValue(this, colorUi);

        //Custom colors ListBox
        var listBox = (ListBox)Activator.CreateInstance(ColorEditorListBoxType);
        //Colors
        listBox.Items.AddRange(new object[] { Color.Red, Color.Green, Color.Blue });
        listBox.DrawMode = DrawMode.OwnerDrawFixed;
        listBox.BorderStyle = BorderStyle.FixedSingle;
        listBox.IntegralHeight = false;
        listBox.Sorted = false;
        listBox.Click  = (sender, e) =>
            OnListClickMethod.Invoke(colorUi, new[] { sender, e });
        //Custom paint
        listBox.DrawItem  = OnListDrawItem;
        //Original paint
        //listBox.DrawItem  =(sender, e) =>
        //    OnListDrawItemMethod.Invoke(colorUi, new[] { sender, e });
        listBox.DrawItem  = OnListDrawItem;
        listBox.KeyDown  = (sender, e) =>
            OnListKeyDownMethod.Invoke(colorUi, new[] { sender, e });
        listBox.Dock = DockStyle.Fill;

        //Add the custom tab page, including the custome colors
        var tabControl = colorUi.Controls.OfType<TabControl>().First();
        var customTabPage = new TabPage();
        customTabPage.Text = "Theme";
        customTabPage.Controls.Add(listBox);
        tabControl.TabPages.Add(customTabPage);
        return base.EditValue(context, provider, value);
    }
    private void OnListDrawItem(object sender, DrawItemEventArgs e)
    {
        var colorNames = new Dictionary<int, string>
        {
            {Color.Red.ToArgb(), "Blood"},
            {Color.Green.ToArgb(), "Life potion"},
            {Color.Blue.ToArgb(), "Water"},
        };
        ListBox lb = (ListBox)sender;
        object value = lb.Items[e.Index];
        e.DrawBackground();
        this.PaintValue(value, e.Graphics,
            new Rectangle(e.Bounds.X   2, e.Bounds.Y   2, 22, e.Bounds.Height - 4));
        e.Graphics.DrawRectangle(SystemPens.WindowText,
            new Rectangle(e.Bounds.X   2, e.Bounds.Y   2, 22 - 1, e.Bounds.Height - 4 - 1));
        var color = (Color)value;
        var name = colorNames.ContainsKey(color.ToArgb()) ? colorNames[color.ToArgb()] : color.Name;
        using (var foreBrush = new SolidBrush(e.ForeColor))
            e.Graphics.DrawString(name, lb.Font, foreBrush, e.Bounds.X   26, e.Bounds.Y);
    }
}
public class MyControl : Control
{
    [Editor(typeof(CustomColorEditor), typeof(UITypeEditor))]
    public Color MyColor { get; set; }
}

Note: It's relying on implementation details of the color editor, for example, in .NET 5 , the member field name is "_colorUI".

  • Related