当你在制作组件时遇到难以构造,解释的或者取值过多,比较复杂的或者难以用一个字符串来表示的视觉效果属性时,你需要实现UI类型编辑器。常见属性ForeColor属性就是一个很好的例子,这种可视化编辑风格使得属性值的选择更方便,更美观!
实现一个定制的UI编辑器:
1.从UITypeEditor基类派生一个新类。
2.对继承自基类的GetEditStyle和EditValue方法进行覆盖。
具体实现:
1.访问属性浏览器的UI显示服务IWindowsFormsEditorService。
2.创建该编辑器UI实现的一个实例。
3.把当前属性的值传递给你在第2步创建的UI编辑器控件。
4.请求属性浏览器显示这个UI编辑器控件。
5.选择一个新的属性值并关闭这个UI编辑器控件。
6.从这个编辑器返回,返回值就是你在第5步选择的新属性值。
还是以ClockControl为例(参考前文:《.Net窗体设计阶段的功能集成问答》和《类型转换器的定制》,附源代码),为它的Face属性提供一个下拉式编辑器:
1

public class FaceEditor : System.Drawing.Design.UITypeEditor
{2

public override UITypeEditorEditStyle GetEditStyle(ITypeDescriptorContext context)
{3

if( context != null )
{4
return UITypeEditorEditStyle.DropDown;5
}6
return base.GetEditStyle(context);7
}8

public override object EditValue(ITypeDescriptorContext context, IServiceProvider provider, object value)
{9

10

if( (context != null) && (provider != null) )
{11
// Access the property browser抯 UI display service, IWindowsFormsEditorService12
IWindowsFormsEditorService editorService = (IWindowsFormsEditorService)provider.GetService(typeof(IWindowsFormsEditorService));13

14

if( editorService != null )
{15
// Create an instance of the UI editor control, passing a reference to the editor service16
FaceEditorControl dropDownEditor = new FaceEditorControl(editorService);17

18
// Pass the UI editor control the current property value19
dropDownEditor.Face = (ClockFace)value;20

21
// Display the UI editor control22
editorService.DropDownControl(dropDownEditor);23

24
// Return the new property value from the UI editor control25
return dropDownEditor.Face;26
}27
}28
return base.EditValue(context, provider, value);29
}30
}1

/**//// <summary>2
/// Summary description for FaceEditorControl.3
/// </summary>4

internal class FaceEditorControl : System.Windows.Forms.UserControl
{5
private System.Windows.Forms.PictureBox picDigital;6
private System.Windows.Forms.PictureBox picAnalog;7
private System.Windows.Forms.PictureBox picBoth;8

/**//// <summary> 9
/// Required designer variable.10
/// </summary>11
private System.ComponentModel.Container components = null;12

13
public FaceEditorControl()14

{15
// This call is required by the Windows.Forms Form Designer.16
InitializeComponent();17

18
// TODO: Add any initialization after the InitForm call19

20
}21

22

/**//// <summary> 23
/// Clean up any resources being used.24
/// </summary>25
protected override void Dispose( bool disposing )26

{27
if( disposing )28

{29
if(components != null)30

{31
components.Dispose();32
}33
}34
base.Dispose( disposing );35
}36

37

Component Designer generated code#region Component Designer generated code38

/**//// <summary> 39
/// Required method for Designer support - do not modify 40
/// the contents of this method with the code editor.41
/// </summary>42
private void InitializeComponent()43

{44
System.Resources.ResourceManager resources = new System.Resources.ResourceManager(typeof(FaceEditorControl));45
this.picDigital = new System.Windows.Forms.PictureBox();46
this.picAnalog = new System.Windows.Forms.PictureBox();47
this.picBoth = new System.Windows.Forms.PictureBox();48
this.SuspendLayout();49
// 50
// picDigital51
// 52
this.picDigital.BackColor = System.Drawing.SystemColors.Highlight;53
this.picDigital.BorderStyle = System.Windows.Forms.BorderStyle.Fixed3D;54
this.picDigital.Image = ((System.Drawing.Bitmap)(resources.GetObject("picDigital.Image")));55
this.picDigital.Location = new System.Drawing.Point(152, 8);56
this.picDigital.Name = "picDigital";57
this.picDigital.Size = new System.Drawing.Size(65, 65);58
this.picDigital.TabIndex = 8;59
this.picDigital.TabStop = false;60
this.picDigital.Click += new System.EventHandler(this.picDigital_Click);61
// 62
// picAnalog63
// 64
this.picAnalog.BackColor = System.Drawing.SystemColors.Highlight;65
this.picAnalog.BorderStyle = System.Windows.Forms.BorderStyle.Fixed3D;66
this.picAnalog.Image = ((System.Drawing.Bitmap)(resources.GetObject("picAnalog.Image")));67
this.picAnalog.Location = new System.Drawing.Point(80, 8);68
this.picAnalog.Name = "picAnalog";69
this.picAnalog.Size = new System.Drawing.Size(65, 65);70
this.picAnalog.TabIndex = 7;71
this.picAnalog.TabStop = false;72
this.picAnalog.Click += new System.EventHandler(this.picAnalog_Click);73
// 74
// picBoth75
// 76
this.picBoth.BackColor = System.Drawing.SystemColors.Highlight;77
this.picBoth.BorderStyle = System.Windows.Forms.BorderStyle.Fixed3D;78
this.picBoth.Image = ((System.Drawing.Bitmap)(resources.GetObject("picBoth.Image")));79
this.picBoth.Location = new System.Drawing.Point(8, 8);80
this.picBoth.Name = "picBoth";81
this.picBoth.Size = new System.Drawing.Size(65, 65);82
this.picBoth.TabIndex = 6;83
this.picBoth.TabStop = false;84
this.picBoth.Click += new System.EventHandler(this.picBoth_Click);85
// 86
// FaceEditorControl87
// 88
this.BackColor = System.Drawing.Color.FromArgb(((System.Byte)(236)), ((System.Byte)(233)), ((System.Byte)(216)));89

this.Controls.AddRange(new System.Windows.Forms.Control[]
{90
this.picDigital,91
this.picAnalog,92
this.picBoth});93
this.Name = "FaceEditorControl";94
this.Size = new System.Drawing.Size(223, 80);95
this.ResumeLayout(false);96

97
}98
#endregion99

100
private ClockFace face = ClockFace.Both;101
private IWindowsFormsEditorService editorService = null;102

103

public FaceEditorControl(IWindowsFormsEditorService editorService)
{104
InitializeComponent();105
this.editorService = editorService;106
}107

108

public ClockFace Face
{109

get
{ return face; }110

set
{ 111
face = value;112

if( face == ClockFace.Both )
{113
this.picBoth.BackColor = Color.Red;114
return;115
}116

if( face == ClockFace.Analog )
{117
this.picAnalog.BackColor = Color.Red;118
return;119
}120

if( face == ClockFace.Digital )
{121
this.picDigital.BackColor = Color.Red;122
return;123
}124
}125
}126

127

private void picBoth_Click(object sender, System.EventArgs e)
{128
face = ClockFace.Both;129

130
// Close the UI editor upon value selection131
editorService.CloseDropDown();132
}133

134

private void picAnalog_Click(object sender, System.EventArgs e)
{135
face = ClockFace.Analog;136

137
// Close the UI editor upon value selection138
editorService.CloseDropDown();139
}140

141

private void picDigital_Click(object sender, System.EventArgs e)
{142
face = ClockFace.Digital;143

144
// Close the UI editor upon value selection145
editorService.CloseDropDown();146
}147

148

protected override void OnPaint(PaintEventArgs pe)
{149

150
// Get currently selected control151
PictureBox selected;152
if( face == ClockFace.Both ) selected = this.picBoth;153
else if( face == ClockFace.Analog ) selected = this.picAnalog;154
else selected = this.picDigital;155

156
// Paint the border157
Graphics g = pe.Graphics;158

using( Pen pen = new Pen(Color.Gray, 1) )
{159
pen.DashStyle = DashStyle.Dash;160
g.DrawLine( pen, new Point(selected.Left - 2, selected.Top - 2), new Point(selected.Left + selected.Width + 1, selected.Top - 2));161
g.DrawLine( pen, new Point(selected.Left + selected.Width + 1, selected.Top - 2), new Point(selected.Left + selected.Width + 1, selected.Top + selected.Height + 1));162
g.DrawLine( pen, new Point(selected.Left + selected.Width + 1, selected.Top + selected.Height + 1), new Point(selected.Left - 2, selected.Top + selected.Height + 1));163
g.DrawLine( pen, new Point(selected.Left - 2, selected.Top + selected.Height + 1), new Point(selected.Left - 2, selected.Top - 2));164
}165
base.OnPaint(pe);166
}167
}