What I am trying to do is to add a custom tab with custom colors into the ColorUI class
of
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.
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".