1 // 2 // System.ComponentModel.Design.Serialization.BasicDesignerLoader 3 // 4 // Authors: 5 // Ivan N. Zlatev (contact i-nZ.net) 6 // 7 // (C) 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; 35 using System.Windows.Forms; 36 37 namespace System.ComponentModel.Design.Serialization 38 { 39 public abstract class BasicDesignerLoader : DesignerLoader, IDesignerLoaderService 40 { 41 42 [Flags] 43 protected enum ReloadOptions 44 { 45 Default, 46 Force, 47 ModifyOnError, 48 NoFlush 49 } 50 51 private bool _loaded; 52 private bool _loading; 53 private IDesignerLoaderHost _host; 54 private int _dependenciesCount; 55 private bool _notificationsEnabled; 56 private bool _modified; 57 private string _baseComponentClassName; 58 private DesignerSerializationManager _serializationMananger; 59 private bool _flushing; 60 private bool _reloadScheduled; 61 private ReloadOptions _reloadOptions; 62 BasicDesignerLoader()63 protected BasicDesignerLoader () 64 { 65 _loading = _loaded = _flushing = _reloadScheduled = false; 66 _host = null; 67 _notificationsEnabled = false; 68 _modified = false; 69 _dependenciesCount = 0; 70 } 71 Initialize()72 protected virtual void Initialize () 73 { 74 _serializationMananger = new DesignerSerializationManager (_host); 75 76 DesignSurfaceServiceContainer serviceContainer = _host.GetService (typeof (IServiceContainer)) as DesignSurfaceServiceContainer; 77 if (serviceContainer != null) { 78 serviceContainer.AddService (typeof (IDesignerLoaderService), (IDesignerLoaderService) this); 79 serviceContainer.AddNonReplaceableService (typeof (IDesignerSerializationManager), _serializationMananger); 80 } 81 } 82 BeginLoad(IDesignerLoaderHost host)83 public override void BeginLoad (IDesignerLoaderHost host) 84 { 85 if (host == null) 86 throw new ArgumentNullException ("host"); 87 if (_loaded) 88 throw new InvalidOperationException ("Already loaded."); 89 if (_host != null && _host != host) 90 throw new InvalidOperationException ("Trying to load with a different host"); 91 92 if (_host == null) { // beingload is called on reload - no need to initialize twice. 93 _host = host; 94 Initialize (); 95 } 96 IDisposable session = _serializationMananger.CreateSession (); 97 98 IDesignerLoaderService loader = _host.GetService (typeof (IDesignerLoaderService)) as IDesignerLoaderService; 99 100 if (loader != null) { 101 _dependenciesCount = -1; 102 loader.AddLoadDependency (); 103 } else { 104 OnBeginLoad (); 105 } 106 107 bool successful = true; 108 109 try { 110 PerformLoad (_serializationMananger); 111 } catch (Exception e) { 112 successful = false; 113 _serializationMananger.Errors.Add (e); 114 } 115 116 if (loader != null) 117 loader.DependentLoadComplete (successful, _serializationMananger.Errors); 118 else 119 OnEndLoad (successful, _serializationMananger.Errors); 120 121 session.Dispose (); 122 } 123 PerformLoad(IDesignerSerializationManager serializationManager)124 protected abstract void PerformLoad (IDesignerSerializationManager serializationManager); 125 OnBeginLoad()126 protected virtual void OnBeginLoad () 127 { 128 _loading = true; 129 } 130 OnEndLoad(bool successful, ICollection errors)131 protected virtual void OnEndLoad (bool successful, ICollection errors) 132 { 133 _host.EndLoad (_baseComponentClassName, successful, errors); 134 135 if (successful) { 136 _loaded = true; 137 EnableComponentNotification (true); 138 } else { 139 if (_reloadScheduled) { // we are reloading 140 bool modify = ((_reloadOptions & ReloadOptions.ModifyOnError) == ReloadOptions.ModifyOnError); 141 if (modify) { 142 OnModifying (); 143 this.Modified = true; 144 } 145 } 146 } 147 _loading = false; 148 } 149 150 public override bool Loading { 151 get { return _loading; } 152 } 153 154 protected IDesignerLoaderHost LoaderHost { 155 get { return _host; } 156 } 157 158 protected virtual bool Modified { 159 get { return _modified; } 160 set { _modified = value; } 161 } 162 163 protected object PropertyProvider { 164 get { 165 if (!_loaded) 166 throw new InvalidOperationException ("host not initialized"); 167 return _serializationMananger.PropertyProvider; 168 } 169 set { 170 if (!_loaded) 171 throw new InvalidOperationException ("host not initialized"); 172 _serializationMananger.PropertyProvider = value; 173 } 174 } 175 176 protected bool ReloadPending { 177 get { return _reloadScheduled; } 178 } 179 EnableComponentNotification(bool enable)180 protected virtual bool EnableComponentNotification (bool enable) 181 { 182 if (!_loaded) 183 throw new InvalidOperationException ("host not initialized"); 184 185 IComponentChangeService service = _host.GetService (typeof (IComponentChangeService)) as IComponentChangeService; 186 if (service != null && _notificationsEnabled != enable) { 187 if (enable) { 188 service.ComponentAdding += new ComponentEventHandler (OnComponentAdding); 189 service.ComponentAdded += new ComponentEventHandler (OnComponentAdded); 190 service.ComponentRemoving += new ComponentEventHandler (OnComponentRemoving); 191 service.ComponentRemoved += new ComponentEventHandler (OnComponentRemoved); 192 service.ComponentChanging += new ComponentChangingEventHandler (OnComponentChanging); 193 service.ComponentChanged += new ComponentChangedEventHandler (OnComponentChanged); 194 service.ComponentRename += new ComponentRenameEventHandler (OnComponentRename); 195 } else { 196 service.ComponentAdding -= new ComponentEventHandler (OnComponentAdding); 197 service.ComponentAdded -= new ComponentEventHandler (OnComponentAdded); 198 service.ComponentRemoving -= new ComponentEventHandler (OnComponentRemoving); 199 service.ComponentRemoved -= new ComponentEventHandler (OnComponentRemoved); 200 service.ComponentChanging -= new ComponentChangingEventHandler (OnComponentChanging); 201 service.ComponentChanged -= new ComponentChangedEventHandler (OnComponentChanged); 202 service.ComponentRename -= new ComponentRenameEventHandler (OnComponentRename); 203 } 204 } 205 return _notificationsEnabled == true ? true : false; 206 } 207 OnComponentAdded(object sender, ComponentEventArgs args)208 private void OnComponentAdded (object sender, ComponentEventArgs args) 209 { 210 if (!_loading && _loaded) 211 this.Modified = true; 212 } 213 OnComponentRemoved(object sender, ComponentEventArgs args)214 private void OnComponentRemoved (object sender, ComponentEventArgs args) 215 { 216 if (!_loading && _loaded) 217 this.Modified = true; 218 } 219 OnComponentAdding(object sender, ComponentEventArgs args)220 private void OnComponentAdding (object sender, ComponentEventArgs args) 221 { 222 if (!_loading && _loaded) 223 OnModifying (); 224 } 225 OnComponentRemoving(object sender, ComponentEventArgs args)226 private void OnComponentRemoving (object sender, ComponentEventArgs args) 227 { 228 if (!_loading && _loaded) 229 OnModifying (); 230 } 231 OnComponentChanged(object sender, ComponentChangedEventArgs args)232 private void OnComponentChanged (object sender, ComponentChangedEventArgs args) 233 { 234 if (!_loading && _loaded) 235 this.Modified = true; 236 } 237 OnComponentChanging(object sender, ComponentChangingEventArgs args)238 private void OnComponentChanging (object sender, ComponentChangingEventArgs args) 239 { 240 if (!_loading && _loaded) 241 OnModifying (); 242 } 243 OnComponentRename(object sender, ComponentRenameEventArgs args)244 private void OnComponentRename (object sender, ComponentRenameEventArgs args) 245 { 246 if (!_loading && _loaded) { 247 OnModifying (); 248 this.Modified = true; 249 } 250 } 251 Flush()252 public override void Flush () 253 { 254 if (!_loaded) 255 throw new InvalidOperationException ("host not initialized"); 256 257 if (!_flushing && this.Modified) { 258 _flushing = true; 259 using ((IDisposable)_serializationMananger.CreateSession ()) { 260 try { 261 PerformFlush (_serializationMananger); 262 } catch (Exception e) { 263 _serializationMananger.Errors.Add (e); 264 ReportFlushErrors (_serializationMananger.Errors); 265 } 266 } 267 _flushing = false; 268 } 269 } 270 PerformFlush(IDesignerSerializationManager serializationManager)271 protected abstract void PerformFlush (IDesignerSerializationManager serializationManager); 272 273 // MSDN: The default implementation always returns true. IsReloadNeeded()274 protected virtual bool IsReloadNeeded () 275 { 276 return true; 277 } 278 279 OnBeginUnload()280 protected virtual void OnBeginUnload () 281 { 282 } 283 OnModifying()284 protected virtual void OnModifying () 285 { 286 } 287 288 // MSDN: reloads are performed at idle time Reload(ReloadOptions flags)289 protected void Reload (ReloadOptions flags) 290 { 291 if (!_reloadScheduled) { 292 _reloadScheduled = true; 293 _reloadOptions = flags; 294 bool force = ((flags & ReloadOptions.Force) == ReloadOptions.Force); 295 if (force) 296 ReloadCore (); 297 else 298 Application.Idle += new EventHandler (OnIdle); 299 } 300 } 301 OnIdle(object sender, EventArgs args)302 private void OnIdle (object sender, EventArgs args) 303 { 304 Application.Idle -= new EventHandler (OnIdle); 305 ReloadCore (); 306 } 307 ReloadCore()308 private void ReloadCore () 309 { 310 bool flush = !((_reloadOptions & ReloadOptions.NoFlush) == ReloadOptions.NoFlush); 311 312 if (flush) 313 Flush (); 314 Unload (); 315 _host.Reload (); 316 BeginLoad (_host); // calls EndLoad, which will check for ReloadOptions.ModifyOnError 317 _reloadScheduled = false; 318 } 319 Unload()320 private void Unload () 321 { 322 if (_loaded) { 323 OnBeginUnload (); 324 EnableComponentNotification (false); 325 _loaded = false; 326 _baseComponentClassName = null; 327 } 328 } 329 330 331 // The default implementation of ReportFlushErrors raises the last exception in the collection. 332 // ReportFlushErrors(ICollection errors)333 protected virtual void ReportFlushErrors (ICollection errors) 334 { 335 object last = null; 336 foreach (object o in errors) 337 last = o; 338 throw (Exception)last; 339 } 340 341 // Must be called during PerformLoad by subclasses. SetBaseComponentClassName(string name)342 protected void SetBaseComponentClassName (string name) 343 { 344 if (name == null) 345 throw new ArgumentNullException ("name"); 346 _baseComponentClassName = name; 347 } 348 349 #region IDesignerLoaderService implementation 350 IDesignerLoaderService.AddLoadDependency()351 void IDesignerLoaderService.AddLoadDependency () 352 { 353 _dependenciesCount++; 354 if (_dependenciesCount == 0) { 355 _dependenciesCount = 1; 356 OnBeginLoad (); 357 } 358 } 359 IDesignerLoaderService.DependentLoadComplete(bool successful, ICollection errorCollection)360 void IDesignerLoaderService.DependentLoadComplete (bool successful, ICollection errorCollection) 361 { 362 if (_dependenciesCount == 0) 363 throw new InvalidOperationException ("dependencies == 0"); 364 365 _dependenciesCount--; 366 if (_dependenciesCount == 0) { 367 OnEndLoad (successful, errorCollection); 368 } 369 } 370 IDesignerLoaderService.Reload()371 bool IDesignerLoaderService.Reload () 372 { 373 if (_dependenciesCount == 0) { 374 this.Reload (ReloadOptions.Force); 375 return true; 376 } 377 return false; 378 } 379 #endregion 380 GetService(Type serviceType)381 protected object GetService (Type serviceType) 382 { 383 if (_host != null) 384 return _host.GetService (serviceType); 385 return null; 386 } 387 Dispose()388 public override void Dispose () 389 { 390 this.LoaderHost.RemoveService (typeof (IDesignerLoaderService)); 391 Unload (); 392 } 393 } 394 } 395 396