当你在制作组件时遇到难以构造,解释的或者取值过多,比较复杂的或者难以用一个字符串来表示的视觉效果属性时,你需要实现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属性提供一个下拉式编辑器:
FaceEditor
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, IWindowsFormsEditorService
12 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 service
16 FaceEditorControl dropDownEditor = new FaceEditorControl(editorService);
17
18 // Pass the UI editor control the current property value
19 dropDownEditor.Face = (ClockFace)value;
20
21 // Display the UI editor control
22 editorService.DropDownControl(dropDownEditor);
23
24 // Return the new property value from the UI editor control
25 return dropDownEditor.Face;
26 }
27 }
28 return base.EditValue(context, provider, value);
29 }
30 }
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, IWindowsFormsEditorService
12 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 service
16 FaceEditorControl dropDownEditor = new FaceEditorControl(editorService);
17
18 // Pass the UI editor control the current property value
19 dropDownEditor.Face = (ClockFace)value;
20
21 // Display the UI editor control
22 editorService.DropDownControl(dropDownEditor);
23
24 // Return the new property value from the UI editor control
25 return dropDownEditor.Face;
26 }
27 }
28 return base.EditValue(context, provider, value);
29 }
30 }
FaceEditorControl
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 call
19
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 code
38 /**//// <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 // picDigital
51 //
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 // picAnalog
63 //
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 // picBoth
75 //
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 // FaceEditorControl
87 //
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 #endregion
99
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 selection
131 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 selection
138 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 selection
145 editorService.CloseDropDown();
146 }
147
148 protected override void OnPaint(PaintEventArgs pe) {
149
150 // Get currently selected control
151 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 border
157 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 }
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 call
19
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 code
38 /**//// <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 // picDigital
51 //
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 // picAnalog
63 //
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 // picBoth
75 //
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 // FaceEditorControl
87 //
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 #endregion
99
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 selection
131 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 selection
138 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 selection
145 editorService.CloseDropDown();
146 }
147
148 protected override void OnPaint(PaintEventArgs pe) {
149
150 // Get currently selected control
151 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 border
157 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 }