2 // System.ComponentModel.Design.DesignerHost
5 // Ivan N. Zlatev (contact i-nZ.net)
7 // (C) 2006-2007 Ivan N. Zlatev
10 // Permission is hereby granted, free of charge, to any person obtaining
11 // a copy of this software and associated documentation files (the
12 // "Software"), to deal in the Software without restriction, including
13 // without limitation the rights to use, copy, modify, merge, publish,
14 // distribute, sublicense, and/or sell copies of the Software, and to
15 // permit persons to whom the Software is furnished to do so, subject to
16 // the following conditions:
18 // The above copyright notice and this permission notice shall be
19 // included in all copies or substantial portions of the Software.
21 // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
22 // EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
23 // MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
24 // NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
25 // LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
26 // OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
27 // WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
33 using System.Collections;
34 using System.ComponentModel;
35 using System.ComponentModel.Design.Serialization;
36 using System.Windows.Forms.Design;
37 using System.Reflection;
39 namespace System.ComponentModel.Design
42 // A container for components and their designers
44 internal sealed class DesignerHost : Container, IDesignerLoaderHost, IDesignerHost, IServiceProvider, IComponentChangeService
48 #region DesignerHostTransaction : DesignerTransaction
50 private enum TransactionAction
56 private sealed class DesignerHostTransaction : DesignerTransaction
59 DesignerHost _designerHost;
61 public DesignerHostTransaction (DesignerHost host, string description) : base (description)
66 protected override void OnCancel ()
68 _designerHost.OnTransactionClosing (this, TransactionAction.Cancel);
69 _designerHost.OnTransactionClosed (this, TransactionAction.Cancel);
72 protected override void OnCommit ()
74 _designerHost.OnTransactionClosing (this, TransactionAction.Commit);
75 _designerHost.OnTransactionClosed (this, TransactionAction.Commit);
78 } // DesignerHostTransaction
83 private IServiceProvider _serviceProvider;
84 private Hashtable _designers;
85 private Stack _transactions;
86 private IServiceContainer _serviceContainer;
87 private bool _loading;
89 public DesignerHost (IServiceProvider serviceProvider)
91 if (serviceProvider == null)
92 throw new ArgumentNullException ("serviceProvider");
94 _serviceProvider = serviceProvider;
95 _serviceContainer = serviceProvider.GetService (typeof (IServiceContainer)) as IServiceContainer;
96 _designers = new Hashtable ();
97 _transactions = new Stack ();
104 // XXX: More validation here?
105 // (e.g: Make use of a potentially existing INameCreationService)
107 public override void Add (IComponent component, string name)
109 AddPreProcess (component, name);
110 base.Add (component, name);
111 AddPostProcess (component, name);
114 internal void AddPreProcess (IComponent component, string name)
116 if (ComponentAdding != null)
117 ComponentAdding (this, new ComponentEventArgs (component));
120 internal void AddPostProcess (IComponent component, string name)
124 if (_rootComponent == null) {
125 _rootComponent = component;
126 designer = this.CreateDesigner (component, true);
129 designer = this.CreateDesigner (component, false);
132 if (designer != null) {
133 _designers[component] = designer;
134 designer.Initialize (component);
136 IUIService uiService = GetService (typeof (IUIService)) as IUIService;
137 if (uiService != null) {
138 uiService.ShowError ("Unable to load a designer for component type '" +
139 component.GetType ().Name + "'");
141 this.DestroyComponent (component);
144 // Activate the host and design surface once the root component is added to
145 // the container and its designer is loaded and added to the designers collection
146 if (component == _rootComponent)
149 if (component is IExtenderProvider) {
150 IExtenderProviderService service = this.GetService (typeof (IExtenderProviderService)) as IExtenderProviderService;
152 service.AddExtenderProvider ((IExtenderProvider) component);
155 if (ComponentAdded != null)
156 ComponentAdded (this, new ComponentEventArgs (component));
159 public override void Remove (IComponent component)
161 DesignerTransaction transaction = this.CreateTransaction ("Remove " + component.Site.Name);
162 RemovePreProcess (component);
163 base.Remove (component);
164 RemovePostProcess (component);
165 transaction.Commit ();
168 internal void RemovePreProcess (IComponent component)
170 if (ComponentRemoving != null)
171 ComponentRemoving (this, new ComponentEventArgs (component));
173 IDesigner designer = _designers[component] as IDesigner;
174 if (designer != null)
177 _designers.Remove (component);
179 if (component == _rootComponent)
180 _rootComponent = null;
182 if (component is IExtenderProvider) {
183 IExtenderProviderService service = GetService (typeof (IExtenderProviderService)) as IExtenderProviderService;
185 service.RemoveExtenderProvider ((IExtenderProvider) component);
189 internal void RemovePostProcess (IComponent component)
191 if (ComponentRemoved != null)
192 ComponentRemoved (this, new ComponentEventArgs (component));
195 protected override ISite CreateSite (IComponent component, string name)
198 INameCreationService nameService = this.GetService (typeof (INameCreationService)) as INameCreationService;
199 if (nameService != null)
200 name = nameService.CreateName (this, component.GetType ());
202 return new DesignModeSite (component, name, this, this);
208 #region IDesignerHost
210 private IComponent _rootComponent;
212 public IContainer Container {
216 public bool InTransaction {
218 if (_transactions != null && _transactions.Count > 0)
225 public bool Loading {
226 get { return _loading; }
229 public IComponent RootComponent {
230 get { return _rootComponent; }
233 public string RootComponentClassName {
235 if (_rootComponent != null)
236 return ((object)_rootComponent).GetType ().AssemblyQualifiedName;
242 public string TransactionDescription {
244 if (_transactions != null && _transactions.Count > 0)
245 return ((DesignerHostTransaction) _transactions.Peek()).Description;
252 // GUI loading in the designer should be done after the Activated event is raised.
254 public void Activate ()
256 ISelectionService selectionService = GetService (typeof (ISelectionService)) as ISelectionService;
258 // Set the Primary Selection to be the root component
260 if (selectionService != null)
261 selectionService.SetSelectedComponents (new IComponent[] { _rootComponent });
263 if (Activated != null)
264 Activated (this, EventArgs.Empty);
267 public IComponent CreateComponent (Type componentClass)
269 return CreateComponent (componentClass, null);
272 public IComponent CreateComponent (Type componentClass, string name)
274 if (componentClass == null)
275 throw new ArgumentNullException ("componentClass");
277 else if (!typeof(IComponent).IsAssignableFrom(componentClass))
278 throw new ArgumentException ("componentClass");
280 IComponent component = this.CreateInstance (componentClass) as IComponent;
281 this.Add (component, name);
286 internal object CreateInstance (Type type)
289 throw new System.ArgumentNullException ("type");
291 // FIXME: Should I use TypeDescriptor.CreateInstance() for 2.0 ?
293 return Activator.CreateInstance (type, BindingFlags.CreateInstance | BindingFlags.Public
294 | BindingFlags.Instance, null, null, null);
297 internal IDesigner CreateDesigner (IComponent component, bool rootDesigner)
299 if (component == null)
300 throw new System.ArgumentNullException ("component");
303 //return TypeDescriptor.CreateDesigner (component, typeof (IRootDesigner));
304 return this.CreateDesigner (component, typeof (IRootDesigner));
307 //return TypeDescriptor.CreateDesigner (component, typeof (IDesigner));
308 return this.CreateDesigner (component, typeof (IDesigner));
312 // Since most of the specific designers are missing this temporary method
313 // will fallback to the first available designer type in the type's base types
315 private IDesigner CreateDesigner (IComponent component, Type designerBaseType)
317 IDesigner instance = null;
318 AttributeCollection attributes = TypeDescriptor.GetAttributes (component);
320 foreach (Attribute attribute in attributes) {
321 DesignerAttribute designerAttr = attribute as DesignerAttribute;
322 if (designerAttr != null &&
323 (designerBaseType.FullName == designerAttr.DesignerBaseTypeName ||
324 designerBaseType.AssemblyQualifiedName == designerAttr.DesignerBaseTypeName)) {
325 Type type = Type.GetType (designerAttr.DesignerTypeName);
326 if (type == null && designerBaseType == typeof (IRootDesigner))
327 type = typeof (System.Windows.Forms.Design.DocumentDesigner);
329 instance = (IDesigner) Activator.CreateInstance (type);
334 if (instance == null) {
335 Type baseType = component.GetType ().BaseType;
337 attributes = TypeDescriptor.GetAttributes (baseType);
338 foreach (Attribute attribute in attributes) {
339 DesignerAttribute designerAttr = attribute as DesignerAttribute;
340 if (designerAttr != null &&
341 (designerBaseType.FullName == designerAttr.DesignerBaseTypeName ||
342 designerBaseType.AssemblyQualifiedName == designerAttr.DesignerBaseTypeName)) {
343 Type type = Type.GetType (designerAttr.DesignerTypeName);
345 instance = (IDesigner) Activator.CreateInstance (type);
349 baseType = baseType.BaseType;
350 } while (instance == null && baseType != null);
356 public void DestroyComponent (IComponent component)
358 if (component.Site != null && component.Site.Container == this) {
359 this.Remove (component); // takes care for the designer as well
360 component.Dispose ();
364 public IDesigner GetDesigner (IComponent component)
366 if (component == null)
367 throw new ArgumentNullException ("component");
369 return _designers[component] as IDesigner;
372 public DesignerTransaction CreateTransaction ()
374 return CreateTransaction (null);
377 public DesignerTransaction CreateTransaction (string description)
379 if (TransactionOpening != null)
380 TransactionOpening (this, EventArgs.Empty);
382 DesignerHostTransaction transaction = new DesignerHostTransaction (this, description);
383 _transactions.Push (transaction);
385 if (TransactionOpened != null)
386 TransactionOpened (this, EventArgs.Empty);
392 public Type GetType (string typeName)
395 ITypeResolutionService s = GetService (typeof (ITypeResolutionService)) as ITypeResolutionService;
398 result = s.GetType (typeName);
400 result = Type.GetType (typeName);
405 // Take care of disposing the designer the base.Dispose will cleanup
408 protected override void Dispose (bool disposing)
411 base.Dispose (disposing);
415 public event EventHandler Activated;
416 public event EventHandler Deactivated;
417 public event EventHandler LoadComplete;
418 public event DesignerTransactionCloseEventHandler TransactionClosed;
419 public event DesignerTransactionCloseEventHandler TransactionClosing;
420 public event EventHandler TransactionOpened;
421 public event EventHandler TransactionOpening;
423 private void OnTransactionClosing (DesignerHostTransaction raiser, TransactionAction action)
426 bool lastTransaction = false;
428 if (_transactions.Peek () != raiser)
429 throw new InvalidOperationException ("Current transaction differs from the one a commit was requested for.");
431 if (_transactions.Count == 1)
432 lastTransaction = true;
433 if (action == TransactionAction.Commit)
436 if (TransactionClosing != null)
437 TransactionClosing (this, new DesignerTransactionCloseEventArgs (commit, lastTransaction));
440 private void OnTransactionClosed (DesignerHostTransaction raiser, TransactionAction action)
443 bool lastTransaction = false;
445 if (_transactions.Peek () != raiser)
446 throw new InvalidOperationException ("Current transaction differs from the one a commit was requested for.");
448 if (_transactions.Count == 1)
449 lastTransaction = true;
450 if (action == TransactionAction.Commit)
453 _transactions.Pop ();
455 if (TransactionClosed != null)
456 TransactionClosed (this, new DesignerTransactionCloseEventArgs (commit, lastTransaction));
462 #region IDesignerLoaderHost
464 internal event LoadedEventHandler DesignerLoaderHostLoaded;
465 internal event EventHandler DesignerLoaderHostLoading;
466 internal event EventHandler DesignerLoaderHostUnloading;
467 internal event EventHandler DesignerLoaderHostUnloaded;
469 public void EndLoad (string rootClassName, bool successful, ICollection errorCollection)
471 if (DesignerLoaderHostLoaded != null)
472 DesignerLoaderHostLoaded (this, new LoadedEventArgs (successful, errorCollection));
474 if (LoadComplete != null)
475 LoadComplete (this, EventArgs.Empty);
477 _loading = false; // _loading = true is set by the ctor
480 // BasicDesignerLoader invokes this.Reload, then invokes BeginLoad on itself,
481 // then when loading it the loader is done it ends up in this.EndLoad.
482 // At the end of the day Reload is more like Unload.
484 public void Reload ()
488 if (DesignerLoaderHostLoading != null)
489 DesignerLoaderHostLoading (this, EventArgs.Empty);
492 private void Unload ()
494 if (DesignerLoaderHostUnloading != null)
495 DesignerLoaderHostUnloading (this, EventArgs.Empty);
497 IComponent[] components = new IComponent[this.Components.Count];
498 this.Components.CopyTo (components, 0);
500 foreach (IComponent component in components)
501 this.Remove (component);
503 _transactions.Clear ();
505 if (DesignerLoaderHostUnloaded != null)
506 DesignerLoaderHostUnloaded (this, EventArgs.Empty);
512 #region IComponentChangeService
514 public event ComponentEventHandler ComponentAdded;
515 public event ComponentEventHandler ComponentAdding;
516 public event ComponentChangedEventHandler ComponentChanged;
517 public event ComponentChangingEventHandler ComponentChanging;
518 public event ComponentEventHandler ComponentRemoved;
519 public event ComponentEventHandler ComponentRemoving;
520 public event ComponentRenameEventHandler ComponentRename;
523 public void OnComponentChanged (object component, MemberDescriptor member, object oldValue, object newValue)
525 if (ComponentChanged != null)
526 ComponentChanged (this, new ComponentChangedEventArgs (component, member, oldValue, newValue));
529 public void OnComponentChanging (object component, MemberDescriptor member)
531 if (ComponentChanging != null)
532 ComponentChanging (this, new ComponentChangingEventArgs (component, member));
535 internal void OnComponentRename (object component, string oldName, string newName)
537 if (ComponentRename != null)
538 ComponentRename (this, new ComponentRenameEventArgs (component, oldName, newName));
544 #region IServiceContainer
545 // Wrapper around the DesignSurface service container
548 public void AddService (Type serviceType, object serviceInstance)
550 _serviceContainer.AddService (serviceType, serviceInstance);
553 public void AddService (Type serviceType, object serviceInstance, bool promote)
555 _serviceContainer.AddService (serviceType, serviceInstance, promote);
558 public void AddService (Type serviceType, ServiceCreatorCallback callback)
560 _serviceContainer.AddService (serviceType, callback);
563 public void AddService (Type serviceType, ServiceCreatorCallback callback, bool promote)
565 _serviceContainer.AddService (serviceType, callback, promote);
568 public void RemoveService (Type serviceType)
570 _serviceContainer.RemoveService (serviceType);
573 public void RemoveService (Type serviceType, bool promote)
575 _serviceContainer.RemoveService (serviceType, promote);
581 #region IServiceProvider
583 public new object GetService (Type serviceType)
585 if (_serviceProvider != null)
586 return _serviceProvider.GetService (serviceType);