可能更灵活(并且更少黑客)的解决方案将重新创建ColorEditor
正如吉米提到的。我还可能采用完全不同的方法来支持主题颜色,例如创建主题扩展程序提供程序组件,或创建派生控件或其他可能的解决方案。
不管怎样,支持我的上一篇文章,特别是我提到的'您甚至可以向编辑器添加另一个选项卡。',这里我发布了一个示例代码,用于向颜色编辑器添加另一个选项卡,然后您可以看到带有您需要的自定义颜色的自定义选项卡(主题),如下所示:
这是一个真实的屏幕截图;)不完全符合您的要求,但作为示例代码已经足够好了。例如,如果您需要使用颜色的自定义名称,那么您需要更多自定义DrawItem
(就像我在示例中所做的那样),或者从头开始重写控件。
这是代码:
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:它依赖于颜色编辑器的实现细节,例如,在.NET 5+中,成员字段名称是“_colorUI”。