1 // 2 // System.ComponentModel.Design.DesignerHost 3 // 4 // Authors: 5 // Ivan N. Zlatev (contact i-nZ.net) 6 // 7 // (C) 2006-2007 Ivan N. Zlatev 8 9 // 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: 17 // 18 // The above copyright notice and this permission notice shall be 19 // included in all copies or substantial portions of the Software. 20 // 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. 28 // 29 30 31 using System; 32 using System.Collections; 33 using System.ComponentModel; 34 using System.ComponentModel.Design.Serialization; 35 using System.Windows.Forms.Design; 36 using System.Reflection; 37 38 namespace System.ComponentModel.Design 39 { 40 41 // A container for components and their designers 42 // 43 internal sealed class DesignerHost : Container, IDesignerLoaderHost, IDesignerHost, IServiceProvider, IComponentChangeService 44 { 45 46 47 #region DesignerHostTransaction : DesignerTransaction 48 49 private enum TransactionAction 50 { 51 Commit, 52 Cancel 53 } 54 55 private sealed class DesignerHostTransaction : DesignerTransaction 56 { 57 58 DesignerHost _designerHost; 59 DesignerHostTransaction(DesignerHost host, string description)60 public DesignerHostTransaction (DesignerHost host, string description) : base (description) 61 { 62 _designerHost = host; 63 } 64 OnCancel()65 protected override void OnCancel () 66 { 67 _designerHost.OnTransactionClosing (this, TransactionAction.Cancel); 68 _designerHost.OnTransactionClosed (this, TransactionAction.Cancel); 69 } 70 OnCommit()71 protected override void OnCommit () 72 { 73 _designerHost.OnTransactionClosing (this, TransactionAction.Commit); 74 _designerHost.OnTransactionClosed (this, TransactionAction.Commit); 75 } 76 77 } // DesignerHostTransaction 78 79 #endregion 80 81 82 private IServiceProvider _serviceProvider; 83 private Hashtable _designers; 84 private Stack _transactions; 85 private IServiceContainer _serviceContainer; 86 private bool _loading; 87 private bool _unloading; DesignerHost(IServiceProvider serviceProvider)88 public DesignerHost (IServiceProvider serviceProvider) 89 { 90 if (serviceProvider == null) 91 throw new ArgumentNullException ("serviceProvider"); 92 93 _serviceProvider = serviceProvider; 94 _serviceContainer = serviceProvider.GetService (typeof (IServiceContainer)) as IServiceContainer; 95 _designers = new Hashtable (); 96 _transactions = new Stack (); 97 _loading = true; 98 } 99 100 101 #region IContainer 102 103 // XXX: More validation here? 104 // (e.g: Make use of a potentially existing INameCreationService) 105 // Add(IComponent component, string name)106 public override void Add (IComponent component, string name) 107 { 108 AddPreProcess (component, name); 109 base.Add (component, name); 110 AddPostProcess (component, name); 111 } 112 AddPreProcess(IComponent component, string name)113 internal void AddPreProcess (IComponent component, string name) 114 { 115 if (ComponentAdding != null) 116 ComponentAdding (this, new ComponentEventArgs (component)); 117 } 118 AddPostProcess(IComponent component, string name)119 internal void AddPostProcess (IComponent component, string name) 120 { 121 IDesigner designer; 122 123 if (_rootComponent == null) { 124 _rootComponent = component; 125 designer = this.CreateDesigner (component, true); 126 } 127 else { 128 designer = this.CreateDesigner (component, false); 129 } 130 131 if (designer != null) { 132 _designers[component] = designer; 133 designer.Initialize (component); 134 } else { 135 IUIService uiService = GetService (typeof (IUIService)) as IUIService; 136 if (uiService != null) { 137 uiService.ShowError ("Unable to load a designer for component type '" + 138 component.GetType ().Name + "'"); 139 } 140 this.DestroyComponent (component); 141 } 142 143 // Activate the host and design surface once the root component is added to 144 // the container and its designer is loaded and added to the designers collection 145 if (component == _rootComponent) 146 this.Activate (); 147 148 if (component is IExtenderProvider) { 149 IExtenderProviderService service = this.GetService (typeof (IExtenderProviderService)) as IExtenderProviderService; 150 if (service != null) 151 service.AddExtenderProvider ((IExtenderProvider) component); 152 } 153 154 if (ComponentAdded != null) 155 ComponentAdded (this, new ComponentEventArgs (component)); 156 } 157 Remove(IComponent component)158 public override void Remove (IComponent component) 159 { 160 DesignerTransaction transaction = this.CreateTransaction ("Remove " + component.Site.Name); 161 RemovePreProcess (component); 162 base.Remove (component); 163 RemovePostProcess (component); 164 transaction.Commit (); 165 } 166 RemovePreProcess(IComponent component)167 internal void RemovePreProcess (IComponent component) 168 { 169 if (!_unloading && ComponentRemoving != null) 170 ComponentRemoving (this, new ComponentEventArgs (component)); 171 172 IDesigner designer = _designers[component] as IDesigner; 173 if (designer != null) 174 designer.Dispose (); 175 176 _designers.Remove (component); 177 178 if (component == _rootComponent) 179 _rootComponent = null; 180 181 if (component is IExtenderProvider) { 182 IExtenderProviderService service = GetService (typeof (IExtenderProviderService)) as IExtenderProviderService; 183 if (service != null) 184 service.RemoveExtenderProvider ((IExtenderProvider) component); 185 } 186 } 187 RemovePostProcess(IComponent component)188 internal void RemovePostProcess (IComponent component) 189 { 190 if (!_unloading && ComponentRemoved != null) 191 ComponentRemoved (this, new ComponentEventArgs (component)); 192 } 193 CreateSite(IComponent component, string name)194 protected override ISite CreateSite (IComponent component, string name) 195 { 196 if (name == null) { 197 INameCreationService nameService = this.GetService (typeof (INameCreationService)) as INameCreationService; 198 if (nameService != null) 199 name = nameService.CreateName (this, component.GetType ()); 200 } 201 return new DesignModeSite (component, name, this, this); 202 } 203 204 #endregion 205 206 207 #region IDesignerHost 208 209 private IComponent _rootComponent; 210 211 public IContainer Container { 212 get { return this; } 213 } 214 215 public bool InTransaction { 216 get { 217 if (_transactions != null && _transactions.Count > 0) 218 return true; 219 220 return false; 221 } 222 } 223 224 public bool Loading { 225 get { return _loading; } 226 } 227 228 public IComponent RootComponent { 229 get { return _rootComponent; } 230 } 231 232 public string RootComponentClassName { 233 get { 234 if (_rootComponent != null) 235 return ((object)_rootComponent).GetType ().AssemblyQualifiedName; 236 237 return null; 238 } 239 } 240 241 public string TransactionDescription { 242 get { 243 if (_transactions != null && _transactions.Count > 0) 244 return ((DesignerHostTransaction) _transactions.Peek()).Description; 245 246 return null; 247 } 248 } 249 250 251 // GUI loading in the designer should be done after the Activated event is raised. 252 // Activate()253 public void Activate () 254 { 255 ISelectionService selectionService = GetService (typeof (ISelectionService)) as ISelectionService; 256 257 // Set the Primary Selection to be the root component 258 // 259 if (selectionService != null) 260 selectionService.SetSelectedComponents (new IComponent[] { _rootComponent }); 261 262 if (Activated != null) 263 Activated (this, EventArgs.Empty); 264 } 265 CreateComponent(Type componentClass)266 public IComponent CreateComponent (Type componentClass) 267 { 268 return CreateComponent (componentClass, null); 269 } 270 CreateComponent(Type componentClass, string name)271 public IComponent CreateComponent (Type componentClass, string name) 272 { 273 if (componentClass == null) 274 throw new ArgumentNullException ("componentClass"); 275 276 else if (!typeof(IComponent).IsAssignableFrom(componentClass)) 277 throw new ArgumentException ("componentClass"); 278 279 IComponent component = this.CreateInstance (componentClass) as IComponent; 280 this.Add (component, name); 281 282 return component; 283 } 284 CreateInstance(Type type)285 internal object CreateInstance (Type type) 286 { 287 if (type == null) 288 throw new System.ArgumentNullException ("type"); 289 290 // FIXME: Should I use TypeDescriptor.CreateInstance() for 2.0 ? 291 // 292 return Activator.CreateInstance (type, BindingFlags.CreateInstance | BindingFlags.Public 293 | BindingFlags.Instance, null, null, null); 294 } 295 CreateDesigner(IComponent component, bool rootDesigner)296 internal IDesigner CreateDesigner (IComponent component, bool rootDesigner) 297 { 298 if (component == null) 299 throw new System.ArgumentNullException ("component"); 300 301 if (rootDesigner) { 302 //return TypeDescriptor.CreateDesigner (component, typeof (IRootDesigner)); 303 return this.CreateDesigner (component, typeof (IRootDesigner)); 304 } 305 else { 306 //return TypeDescriptor.CreateDesigner (component, typeof (IDesigner)); 307 return this.CreateDesigner (component, typeof (IDesigner)); 308 } 309 } 310 311 // Since most of the specific designers are missing this temporary method 312 // will fallback to the first available designer type in the type's base types 313 // CreateDesigner(IComponent component, Type designerBaseType)314 private IDesigner CreateDesigner (IComponent component, Type designerBaseType) 315 { 316 IDesigner instance = null; 317 AttributeCollection attributes = TypeDescriptor.GetAttributes (component); 318 319 foreach (Attribute attribute in attributes) { 320 DesignerAttribute designerAttr = attribute as DesignerAttribute; 321 if (designerAttr != null && 322 (designerBaseType.FullName == designerAttr.DesignerBaseTypeName || 323 designerBaseType.AssemblyQualifiedName == designerAttr.DesignerBaseTypeName)) { 324 Type type = Type.GetType (designerAttr.DesignerTypeName); 325 if (type == null && designerBaseType == typeof (IRootDesigner)) 326 type = typeof (System.Windows.Forms.Design.DocumentDesigner); 327 if (type != null) 328 instance = (IDesigner) Activator.CreateInstance (type); 329 break; 330 } 331 } 332 333 if (instance == null) { 334 Type baseType = component.GetType ().BaseType; 335 do { 336 attributes = TypeDescriptor.GetAttributes (baseType); 337 foreach (Attribute attribute in attributes) { 338 DesignerAttribute designerAttr = attribute as DesignerAttribute; 339 if (designerAttr != null && 340 (designerBaseType.FullName == designerAttr.DesignerBaseTypeName || 341 designerBaseType.AssemblyQualifiedName == designerAttr.DesignerBaseTypeName)) { 342 Type type = Type.GetType (designerAttr.DesignerTypeName); 343 if (type != null) 344 instance = (IDesigner) Activator.CreateInstance (type); 345 break; 346 } 347 } 348 baseType = baseType.BaseType; 349 } while (instance == null && baseType != null); 350 } 351 352 return instance; 353 } 354 DestroyComponent(IComponent component)355 public void DestroyComponent (IComponent component) 356 { 357 if (component.Site != null && component.Site.Container == this) { 358 this.Remove (component); // takes care for the designer as well 359 component.Dispose (); 360 } 361 } 362 GetDesigner(IComponent component)363 public IDesigner GetDesigner (IComponent component) 364 { 365 if (component == null) 366 throw new ArgumentNullException ("component"); 367 368 return _designers[component] as IDesigner; 369 } 370 CreateTransaction()371 public DesignerTransaction CreateTransaction () 372 { 373 return CreateTransaction (null); 374 } 375 CreateTransaction(string description)376 public DesignerTransaction CreateTransaction (string description) 377 { 378 if (TransactionOpening != null) 379 TransactionOpening (this, EventArgs.Empty); 380 381 DesignerHostTransaction transaction = new DesignerHostTransaction (this, description); 382 _transactions.Push (transaction); 383 384 if (TransactionOpened != null) 385 TransactionOpened (this, EventArgs.Empty); 386 387 return transaction; 388 } 389 390 GetType(string typeName)391 public Type GetType (string typeName) 392 { 393 Type result; 394 ITypeResolutionService s = GetService (typeof (ITypeResolutionService)) as ITypeResolutionService; 395 396 if (s != null) 397 result = s.GetType (typeName); 398 else 399 result = Type.GetType (typeName); 400 401 return result; 402 } 403 404 // Take care of disposing the designer the base.Dispose will cleanup 405 // the components. 406 // Dispose(bool disposing)407 protected override void Dispose (bool disposing) 408 { 409 Unload (); 410 base.Dispose (disposing); 411 } 412 413 414 public event EventHandler Activated; 415 public event EventHandler Deactivated; 416 public event EventHandler LoadComplete; 417 public event DesignerTransactionCloseEventHandler TransactionClosed; 418 public event DesignerTransactionCloseEventHandler TransactionClosing; 419 public event EventHandler TransactionOpened; 420 public event EventHandler TransactionOpening; 421 OnTransactionClosing(DesignerHostTransaction raiser, TransactionAction action)422 private void OnTransactionClosing (DesignerHostTransaction raiser, TransactionAction action) 423 { 424 bool commit = false; 425 bool lastTransaction = false; 426 427 if (_transactions.Peek () != raiser) 428 throw new InvalidOperationException ("Current transaction differs from the one a commit was requested for."); 429 430 if (_transactions.Count == 1) 431 lastTransaction = true; 432 if (action == TransactionAction.Commit) 433 commit = true; 434 435 if (TransactionClosing != null) 436 TransactionClosing (this, new DesignerTransactionCloseEventArgs (commit, lastTransaction)); 437 } 438 OnTransactionClosed(DesignerHostTransaction raiser, TransactionAction action)439 private void OnTransactionClosed (DesignerHostTransaction raiser, TransactionAction action) 440 { 441 bool commit = false; 442 bool lastTransaction = false; 443 444 if (_transactions.Peek () != raiser) 445 throw new InvalidOperationException ("Current transaction differs from the one a commit was requested for."); 446 447 if (_transactions.Count == 1) 448 lastTransaction = true; 449 if (action == TransactionAction.Commit) 450 commit = true; 451 452 _transactions.Pop (); 453 454 if (TransactionClosed != null) 455 TransactionClosed (this, new DesignerTransactionCloseEventArgs (commit, lastTransaction)); 456 } 457 458 #endregion 459 460 461 #region IDesignerLoaderHost 462 463 internal event LoadedEventHandler DesignerLoaderHostLoaded; 464 internal event EventHandler DesignerLoaderHostLoading; 465 internal event EventHandler DesignerLoaderHostUnloading; 466 internal event EventHandler DesignerLoaderHostUnloaded; 467 EndLoad(string rootClassName, bool successful, ICollection errorCollection)468 public void EndLoad (string rootClassName, bool successful, ICollection errorCollection) 469 { 470 if (DesignerLoaderHostLoaded != null) 471 DesignerLoaderHostLoaded (this, new LoadedEventArgs (successful, errorCollection)); 472 473 if (LoadComplete != null) 474 LoadComplete (this, EventArgs.Empty); 475 476 _loading = false; // _loading = true is set by the ctor 477 } 478 479 // BasicDesignerLoader invokes this.Reload, then invokes BeginLoad on itself, 480 // then when loading it the loader is done it ends up in this.EndLoad. 481 // At the end of the day Reload is more like Unload. 482 // Reload()483 public void Reload () 484 { 485 _loading = true; 486 Unload (); 487 if (DesignerLoaderHostLoading != null) 488 DesignerLoaderHostLoading (this, EventArgs.Empty); 489 } 490 Unload()491 private void Unload () 492 { 493 _unloading = true; 494 if (DesignerLoaderHostUnloading != null) 495 DesignerLoaderHostUnloading (this, EventArgs.Empty); 496 497 IComponent[] components = new IComponent[this.Components.Count]; 498 this.Components.CopyTo (components, 0); 499 500 foreach (IComponent component in components) 501 this.Remove (component); 502 503 _transactions.Clear (); 504 505 if (DesignerLoaderHostUnloaded != null) 506 DesignerLoaderHostUnloaded (this, EventArgs.Empty); 507 _unloading = false; 508 } 509 510 #endregion 511 512 513 #region IComponentChangeService 514 515 public event ComponentEventHandler ComponentAdded; 516 public event ComponentEventHandler ComponentAdding; 517 public event ComponentChangedEventHandler ComponentChanged; 518 public event ComponentChangingEventHandler ComponentChanging; 519 public event ComponentEventHandler ComponentRemoved; 520 public event ComponentEventHandler ComponentRemoving; 521 public event ComponentRenameEventHandler ComponentRename; 522 523 OnComponentChanged(object component, MemberDescriptor member, object oldValue, object newValue)524 public void OnComponentChanged (object component, MemberDescriptor member, object oldValue, object newValue) 525 { 526 if (ComponentChanged != null) 527 ComponentChanged (this, new ComponentChangedEventArgs (component, member, oldValue, newValue)); 528 } 529 OnComponentChanging(object component, MemberDescriptor member)530 public void OnComponentChanging (object component, MemberDescriptor member) 531 { 532 if (ComponentChanging != null) 533 ComponentChanging (this, new ComponentChangingEventArgs (component, member)); 534 } 535 OnComponentRename(object component, string oldName, string newName)536 internal void OnComponentRename (object component, string oldName, string newName) 537 { 538 if (ComponentRename != null) 539 ComponentRename (this, new ComponentRenameEventArgs (component, oldName, newName)); 540 } 541 542 #endregion 543 544 545 #region IServiceContainer 546 // Wrapper around the DesignSurface service container 547 // 548 AddService(Type serviceType, object serviceInstance)549 public void AddService (Type serviceType, object serviceInstance) 550 { 551 _serviceContainer.AddService (serviceType, serviceInstance); 552 } 553 AddService(Type serviceType, object serviceInstance, bool promote)554 public void AddService (Type serviceType, object serviceInstance, bool promote) 555 { 556 _serviceContainer.AddService (serviceType, serviceInstance, promote); 557 } 558 AddService(Type serviceType, ServiceCreatorCallback callback)559 public void AddService (Type serviceType, ServiceCreatorCallback callback) 560 { 561 _serviceContainer.AddService (serviceType, callback); 562 } 563 AddService(Type serviceType, ServiceCreatorCallback callback, bool promote)564 public void AddService (Type serviceType, ServiceCreatorCallback callback, bool promote) 565 { 566 _serviceContainer.AddService (serviceType, callback, promote); 567 } 568 RemoveService(Type serviceType)569 public void RemoveService (Type serviceType) 570 { 571 _serviceContainer.RemoveService (serviceType); 572 } 573 RemoveService(Type serviceType, bool promote)574 public void RemoveService (Type serviceType, bool promote) 575 { 576 _serviceContainer.RemoveService (serviceType, promote); 577 } 578 579 #endregion 580 581 582 #region IServiceProvider 583 GetService(Type serviceType)584 public new object GetService (Type serviceType) 585 { 586 if (_serviceProvider != null) 587 return _serviceProvider.GetService (serviceType); 588 return null; 589 } 590 591 #endregion 592 593 } 594 595 } 596