2 // System.ComponentModel.Design.CollectionEditor
5 // Martin Willemoes Hansen (mwh@sysrq.dk)
6 // Andreas Nahr (ClassDevelopment@A-SoftTech.com)
8 // (C) 2003 Martin Willemoes Hansen
9 // (C) 2007 Andreas Nahr
13 // Permission is hereby granted, free of charge, to any person obtaining
14 // a copy of this software and associated documentation files (the
15 // "Software"), to deal in the Software without restriction, including
16 // without limitation the rights to use, copy, modify, merge, publish,
17 // distribute, sublicense, and/or sell copies of the Software, and to
18 // permit persons to whom the Software is furnished to do so, subject to
19 // the following conditions:
21 // The above copyright notice and this permission notice shall be
22 // included in all copies or substantial portions of the Software.
24 // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
25 // EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
26 // MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
27 // NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
28 // LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
29 // OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
30 // WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
35 using System.Reflection;
36 using System.Collections;
37 using System.ComponentModel;
38 using System.Drawing.Design;
39 using System.Windows.Forms;
40 using System.Windows.Forms.Design;
42 namespace System.ComponentModel.Design
44 public class CollectionEditor : UITypeEditor
46 protected abstract class CollectionForm : Form
48 private CollectionEditor editor;
49 private object editValue;
51 public CollectionForm (CollectionEditor editor)
56 protected Type CollectionItemType
58 get { return editor.CollectionItemType; }
61 protected Type CollectionType
63 get { return editor.CollectionType; }
66 protected ITypeDescriptorContext Context
68 get { return editor.Context; }
71 public object EditValue
73 get { return editValue; }
77 OnEditValueChanged ();
81 protected object[] Items
83 get { return editor.GetItems (editValue); }
84 set { editor.SetItems (editValue, value); }
87 protected Type[] NewItemTypes
89 get { return editor.NewItemTypes; }
92 protected bool CanRemoveInstance (object value)
94 return editor.CanRemoveInstance (value);
97 protected virtual bool CanSelectMultipleInstances ()
99 return editor.CanSelectMultipleInstances ();
102 protected object CreateInstance (Type itemType)
104 return editor.CreateInstance (itemType);
107 protected void DestroyInstance (object instance)
109 editor.DestroyInstance (instance);
112 protected virtual void DisplayError (Exception e)
114 MessageBox.Show (e.Message, "Error", MessageBoxButtons.OK, MessageBoxIcon.Information);
117 protected override object GetService (Type serviceType)
119 return editor.GetService (serviceType);
122 protected abstract void OnEditValueChanged ();
124 protected internal virtual DialogResult ShowEditorDialog (IWindowsFormsEditorService edSvc)
126 return edSvc.ShowDialog (this);
130 private class ConcreteCollectionForm : CollectionForm
132 internal class ObjectContainerConverter : TypeConverter
134 private class ObjectContainerPropertyDescriptor : TypeConverter.SimplePropertyDescriptor
136 private AttributeCollection attributes;
138 public ObjectContainerPropertyDescriptor (Type componentType, Type propertyType)
139 : base (componentType, "Value", propertyType)
141 CategoryAttribute cat = new CategoryAttribute (propertyType.Name);
142 attributes = new AttributeCollection (new Attribute[] { cat });
145 public override object GetValue (object component)
147 ObjectContainer container = (ObjectContainer)component;
148 return container.Object;
151 public override void SetValue (object component, object value)
153 ObjectContainer container = (ObjectContainer)component;
154 container.Object = value;
157 public override AttributeCollection Attributes
159 get { return attributes; }
163 public override PropertyDescriptorCollection GetProperties (ITypeDescriptorContext context, object value, Attribute[] attributes)
165 ObjectContainer container = (ObjectContainer)value;
166 ObjectContainerPropertyDescriptor desc = new ObjectContainerPropertyDescriptor (value.GetType (), container.editor.CollectionItemType);
167 PropertyDescriptor[] properties = new PropertyDescriptor[] { desc };
168 PropertyDescriptorCollection pc = new PropertyDescriptorCollection (properties);
172 public override bool GetPropertiesSupported (ITypeDescriptorContext context)
178 [TypeConverter (typeof (ObjectContainerConverter))]
179 private class ObjectContainer
181 internal string Name;
182 internal object Object;
183 internal CollectionEditor editor;
185 public ObjectContainer (string name, object obj, CollectionEditor editor)
189 this.editor = editor;
192 public override string ToString ()
198 private class UpdateableListbox : ListBox
200 public void DoRefreshItem (int index)
202 base.RefreshItem (index);
206 private CollectionEditor editor;
208 private System.Windows.Forms.Label labelMember;
209 private System.Windows.Forms.Label labelProperty;
210 private UpdateableListbox itemsList;
211 private System.Windows.Forms.PropertyGrid itemDisplay;
212 private System.Windows.Forms.Button doClose;
213 private System.Windows.Forms.Button moveUp;
214 private System.Windows.Forms.Button moveDown;
215 private System.Windows.Forms.Button doAdd;
216 private System.Windows.Forms.Button doRemove;
217 private System.Windows.Forms.Button doCancel;
218 private System.Windows.Forms.ComboBox addType;
220 public ConcreteCollectionForm (CollectionEditor editor)
223 this.editor = editor;
225 this.labelMember = new System.Windows.Forms.Label ();
226 this.labelProperty = new System.Windows.Forms.Label ();
227 this.itemsList = new UpdateableListbox ();
228 this.itemDisplay = new System.Windows.Forms.PropertyGrid ();
229 this.doClose = new System.Windows.Forms.Button ();
230 this.moveUp = new System.Windows.Forms.Button ();
231 this.moveDown = new System.Windows.Forms.Button ();
232 this.doAdd = new System.Windows.Forms.Button ();
233 this.doRemove = new System.Windows.Forms.Button ();
234 this.doCancel = new System.Windows.Forms.Button ();
235 this.addType = new System.Windows.Forms.ComboBox ();
236 this.SuspendLayout ();
240 this.labelMember.Location = new System.Drawing.Point (12, 9);
241 this.labelMember.Size = new System.Drawing.Size (55, 13);
242 this.labelMember.Text = "Members:";
246 this.labelProperty.Anchor = ((System.Windows.Forms.AnchorStyles)(((System.Windows.Forms.AnchorStyles.Top | System.Windows.Forms.AnchorStyles.Left)
247 | System.Windows.Forms.AnchorStyles.Right)));
248 this.labelProperty.Location = new System.Drawing.Point (172, 9);
249 this.labelProperty.Size = new System.Drawing.Size (347, 13);
250 this.labelProperty.Text = "Properties:";
254 this.itemsList.Anchor = ((System.Windows.Forms.AnchorStyles)(((System.Windows.Forms.AnchorStyles.Top | System.Windows.Forms.AnchorStyles.Bottom)
255 | System.Windows.Forms.AnchorStyles.Left)));
256 this.itemsList.HorizontalScrollbar = true;
257 this.itemsList.Location = new System.Drawing.Point (12, 25);
258 this.itemsList.SelectionMode = System.Windows.Forms.SelectionMode.MultiExtended;
259 this.itemsList.Size = new System.Drawing.Size (120, 290);
260 this.itemsList.TabIndex = 0;
261 this.itemsList.SelectedIndexChanged += new System.EventHandler (this.itemsList_SelectedIndexChanged);
265 this.itemDisplay.Anchor = ((System.Windows.Forms.AnchorStyles)((((System.Windows.Forms.AnchorStyles.Top | System.Windows.Forms.AnchorStyles.Bottom)
266 | System.Windows.Forms.AnchorStyles.Left)
267 | System.Windows.Forms.AnchorStyles.Right)));
268 this.itemDisplay.HelpVisible = false;
269 this.itemDisplay.Location = new System.Drawing.Point (175, 25);
270 this.itemDisplay.Size = new System.Drawing.Size (344, 314);
271 this.itemDisplay.TabIndex = 6;
272 this.itemDisplay.PropertyValueChanged += new System.Windows.Forms.PropertyValueChangedEventHandler (this.itemDisplay_PropertyValueChanged);
276 this.doClose.Anchor = ((System.Windows.Forms.AnchorStyles)((System.Windows.Forms.AnchorStyles.Bottom | System.Windows.Forms.AnchorStyles.Right)));
277 this.doClose.Location = new System.Drawing.Point (341, 345);
278 this.doClose.Size = new System.Drawing.Size (86, 26);
279 this.doClose.TabIndex = 7;
280 this.doClose.Text = "OK";
281 this.doClose.Click += new System.EventHandler (this.doClose_Click);
285 this.moveUp.Location = new System.Drawing.Point (138, 25);
286 this.moveUp.Size = new System.Drawing.Size (31, 28);
287 this.moveUp.TabIndex = 4;
288 this.moveUp.Text = "Up";
289 this.moveUp.Click += new System.EventHandler (this.moveUp_Click);
293 this.moveDown.Location = new System.Drawing.Point (138, 59);
294 this.moveDown.Size = new System.Drawing.Size (31, 28);
295 this.moveDown.TabIndex = 5;
296 this.moveDown.Text = "Dn";
297 this.moveDown.Click += new System.EventHandler (this.moveDown_Click);
301 this.doAdd.Anchor = ((System.Windows.Forms.AnchorStyles)((System.Windows.Forms.AnchorStyles.Bottom | System.Windows.Forms.AnchorStyles.Left)));
302 this.doAdd.Location = new System.Drawing.Point (12, 346);
303 this.doAdd.Size = new System.Drawing.Size (59, 25);
304 this.doAdd.TabIndex = 1;
305 this.doAdd.Text = "Add";
306 this.doAdd.Click += new System.EventHandler (this.doAdd_Click);
310 this.doRemove.Anchor = ((System.Windows.Forms.AnchorStyles)((System.Windows.Forms.AnchorStyles.Bottom | System.Windows.Forms.AnchorStyles.Left)));
311 this.doRemove.Location = new System.Drawing.Point (77, 346);
312 this.doRemove.Size = new System.Drawing.Size (55, 25);
313 this.doRemove.TabIndex = 2;
314 this.doRemove.Text = "Remove";
315 this.doRemove.Click += new System.EventHandler (this.doRemove_Click);
319 this.doCancel.Anchor = ((System.Windows.Forms.AnchorStyles)((System.Windows.Forms.AnchorStyles.Bottom | System.Windows.Forms.AnchorStyles.Right)));
320 this.doCancel.DialogResult = System.Windows.Forms.DialogResult.Cancel;
321 this.doCancel.Location = new System.Drawing.Point (433, 345);
322 this.doCancel.Size = new System.Drawing.Size (86, 26);
323 this.doCancel.TabIndex = 8;
324 this.doCancel.Text = "Cancel";
325 this.doCancel.Click += new System.EventHandler (this.doCancel_Click);
329 this.addType.Anchor = ((System.Windows.Forms.AnchorStyles)((System.Windows.Forms.AnchorStyles.Bottom | System.Windows.Forms.AnchorStyles.Left)));
330 this.addType.DropDownStyle = System.Windows.Forms.ComboBoxStyle.DropDownList;
331 this.addType.Location = new System.Drawing.Point (12, 319);
332 this.addType.Size = new System.Drawing.Size (120, 21);
333 this.addType.TabIndex = 3;
337 this.AcceptButton = this.doClose;
338 this.CancelButton = this.doCancel;
339 this.ClientSize = new System.Drawing.Size (531, 381);
340 this.ControlBox = false;
341 this.Controls.Add (this.addType);
342 this.Controls.Add (this.doCancel);
343 this.Controls.Add (this.doRemove);
344 this.Controls.Add (this.doAdd);
345 this.Controls.Add (this.moveDown);
346 this.Controls.Add (this.moveUp);
347 this.Controls.Add (this.doClose);
348 this.Controls.Add (this.itemDisplay);
349 this.Controls.Add (this.itemsList);
350 this.Controls.Add (this.labelProperty);
351 this.Controls.Add (this.labelMember);
352 this.HelpButton = true;
353 this.MaximizeBox = false;
354 this.MinimizeBox = false;
355 this.MinimumSize = new System.Drawing.Size (400, 300);
356 this.ShowInTaskbar = false;
357 this.StartPosition = System.Windows.Forms.FormStartPosition.CenterScreen;
358 this.ResumeLayout (false);
361 if (editor.CollectionType.IsGenericType)
362 this.Text = editor.CollectionItemType.Name + " Collection Editor";
364 this.Text = editor.CollectionType.Name + " Collection Editor";
366 this.Text = editor.CollectionType.Name + " Collection Editor";
368 foreach (Type type in editor.NewItemTypes)
369 addType.Items.Add (type.Name);
370 if (addType.Items.Count > 0)
371 addType.SelectedIndex = 0;
374 private void AddItems ()
376 foreach (object o in editor.GetItems (EditValue))
378 this.itemsList.Items.Add (new ObjectContainer (editor.GetDisplayText (o), o, editor));
380 if (itemsList.Items.Count > 0)
381 itemsList.SelectedIndex = 0;
384 private void doClose_Click (object sender, EventArgs e)
386 object[] items = new object[itemsList.Items.Count];
387 for (int i = 0; i < itemsList.Items.Count; i++)
388 items[i] = ((ObjectContainer)itemsList.Items[i]).Object;
389 EditValue = editor.SetItems (EditValue, items);
393 private void doCancel_Click (object sender, EventArgs e)
395 editor.CancelChanges ();
399 private void itemsList_SelectedIndexChanged (object sender, EventArgs e)
401 if (itemsList.SelectedIndex <= 0 || itemsList.SelectedItems.Count > 1)
402 moveUp.Enabled = false;
404 moveUp.Enabled = true;
405 if (itemsList.SelectedIndex > itemsList.Items.Count - 2 || itemsList.SelectedItems.Count > 1)
406 moveDown.Enabled = false;
408 moveDown.Enabled = true;
410 if (itemsList.SelectedIndex == -1)
413 if (itemsList.SelectedItems.Count == 1)
415 ObjectContainer o = (ObjectContainer)itemsList.SelectedItem;
416 if (Type.GetTypeCode (o.Object.GetType ()) != TypeCode.Object)
417 itemDisplay.SelectedObject = o;
419 itemDisplay.SelectedObject = o.Object;
423 object[] items = new object[itemsList.SelectedItems.Count];
424 for (int i = 0; i < itemsList.SelectedItems.Count; i++)
426 ObjectContainer o = (ObjectContainer)itemsList.SelectedItem;
427 if (Type.GetTypeCode (o.Object.GetType ()) != TypeCode.Object)
428 items[i] = ((ObjectContainer)itemsList.SelectedItems[i]);
430 items[i] = ((ObjectContainer)itemsList.SelectedItems[i]).Object;
432 itemDisplay.SelectedObjects = items;
434 labelProperty.Text = ((ObjectContainer)itemsList.SelectedItem).Name + " properties:";
437 private void itemDisplay_PropertyValueChanged (object sender, EventArgs e)
439 int[] indices = new int[itemsList.SelectedIndices.Count];
440 itemsList.SelectedIndices.CopyTo (indices, 0);
441 for (int i = 0; i < indices.Length; i++)
443 ObjectContainer o = (ObjectContainer)itemsList.Items [indices[i]];
444 o.Name = editor.GetDisplayText (o.Object);
445 itemsList.DoRefreshItem (indices[i]);
447 for (int i = 0; i < indices.Length; i++)
448 itemsList.SetSelected (indices[i], true);
451 private void moveUp_Click (object sender, EventArgs e)
453 if (itemsList.SelectedIndex <= 0)
456 object selected = itemsList.SelectedItem;
457 int index = itemsList.SelectedIndex;
458 itemsList.Items.RemoveAt (index);
459 itemsList.Items.Insert (index - 1, selected);
460 itemsList.SelectedIndex = index - 1;
463 private void moveDown_Click (object sender, EventArgs e)
465 if (itemsList.SelectedIndex > itemsList.Items.Count - 2)
468 object selected = itemsList.SelectedItem;
469 int index = itemsList.SelectedIndex;
470 itemsList.Items.RemoveAt (index);
471 itemsList.Items.Insert (index + 1, selected);
472 itemsList.SelectedIndex = index + 1;
475 private void doAdd_Click (object sender, EventArgs e)
480 o = editor.CreateInstance (editor.NewItemTypes[addType.SelectedIndex]);
487 itemsList.Items.Add (new ObjectContainer (editor.GetDisplayText (o), o, editor));
490 private void doRemove_Click (object sender, EventArgs e)
492 if (itemsList.SelectedIndex != -1)
493 itemsList.Items.RemoveAt (itemsList.SelectedIndex);
496 protected override void OnEditValueChanged ()
503 private Type collectionItemType;
504 private Type[] newItemTypes;
505 private ITypeDescriptorContext context;
506 private IServiceProvider provider;
507 private IWindowsFormsEditorService editorService;
509 public CollectionEditor (Type type)
512 this.collectionItemType = CreateCollectionItemType ();
513 this.newItemTypes = CreateNewItemTypes ();
516 protected Type CollectionItemType
518 get { return collectionItemType; }
521 protected Type CollectionType
526 protected ITypeDescriptorContext Context
528 get { return context; }
531 protected virtual string HelpTopic
533 get { return "CollectionEditor"; }
536 protected Type[] NewItemTypes
538 get { return newItemTypes; }
541 protected virtual void CancelChanges ()
545 protected virtual bool CanRemoveInstance (object value)
550 protected virtual bool CanSelectMultipleInstances ()
555 protected virtual CollectionEditor.CollectionForm CreateCollectionForm ()
557 return new ConcreteCollectionForm (this);
560 protected virtual Type CreateCollectionItemType ()
562 PropertyInfo info = type.GetProperty ("Item");
563 return info.PropertyType;
566 protected virtual object CreateInstance (Type itemType)
569 return TypeDescriptor.CreateInstance (provider, itemType, null, null);
571 return Activator.CreateInstance (itemType);
575 protected virtual Type[] CreateNewItemTypes ()
577 return new Type[] { collectionItemType };
580 protected virtual void DestroyInstance (object instance)
582 //FIXME: I've got NO clue what this does and the documentation isn't helpfull either
585 public override object EditValue (ITypeDescriptorContext context, IServiceProvider provider, object value)
587 this.context = context;
588 this.provider = provider;
590 if (context != null && provider != null)
592 editorService = (IWindowsFormsEditorService)provider.GetService (typeof (IWindowsFormsEditorService));
593 if (editorService != null)
595 CollectionForm editorForm = CreateCollectionForm ();
596 editorForm.EditValue = value;
598 editorForm.ShowEditorDialog (editorService);
600 return editorForm.EditValue;
603 return base.EditValue (context, provider, value);
606 protected virtual string GetDisplayText (object value)
611 PropertyInfo nameProperty = value.GetType ().GetProperty ("Name");
612 if (nameProperty != null)
614 string data = (nameProperty.GetValue (value, null)) as string;
616 if (data.Length != 0)
620 if (Type.GetTypeCode (value.GetType ()) == TypeCode.Object)
621 return value.GetType ().Name;
623 return value.ToString ();
626 public override UITypeEditorEditStyle GetEditStyle (ITypeDescriptorContext context)
628 return UITypeEditorEditStyle.Modal;
631 protected virtual object[] GetItems (object editValue)
633 if (editValue == null)
635 ICollection collection = editValue as ICollection;
636 if (collection == null)
637 return new object[0];
639 object[] result = new object[collection.Count];
640 collection.CopyTo (result, 0);
644 protected virtual IList GetObjectsFromInstance (object instance)
646 ArrayList list = new ArrayList ();
651 protected object GetService (Type serviceType)
653 return context.GetService (serviceType);
656 protected virtual object SetItems (object editValue, object[] value)
660 if (editValue == null)
663 if (!(editValue is IList))
664 list = new ArrayList ();
667 list = editValue as IList;
671 foreach (object o in value)
677 protected virtual void ShowHelp ()
679 //TODO: Fixme Add parent and URL
680 Help.ShowHelp (null, "", HelpTopic);