2 // System.ComponentModel.Design.Serialization.DesignerSerializationManager
5 // Ivan N. Zlatev (contact i-nZ.net)
7 // (C) 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.Collections.Generic;
35 using System.Reflection;
36 using System.ComponentModel;
37 using System.ComponentModel.Design;
41 namespace System.ComponentModel.Design.Serialization
44 public class DesignerSerializationManager : IDesignerSerializationManager, IServiceProvider
47 private class Session : IDisposable
50 private DesignerSerializationManager _manager;
52 public Session (DesignerSerializationManager manager)
57 public void Dispose ()
59 _manager.OnSessionDisposed (EventArgs.Empty);
65 public DesignerSerializationManager () : this (null)
69 // This constructor sets the PreserveNames and ValidateRecycledTypes properties to true.
71 public DesignerSerializationManager (IServiceProvider provider)
73 _serviceProvider = provider;
74 _preserveNames = true;
75 _validateRecycledTypes = true;
78 private IServiceProvider _serviceProvider;
79 private bool _preserveNames = false;
80 private bool _validateRecycledTypes = false;
81 private bool _recycleInstances = false;
82 private IContainer _designerContainer = null;
83 private object _propertyProvider = null;
84 private Session _session = null;
85 private ArrayList _errors = null;
86 private List <IDesignerSerializationProvider> _serializationProviders;
87 private Dictionary <Type, object> _serializersCache = null; // componentType - serializer instance
88 private Dictionary <string, object> _instancesByNameCache = null; // name - instance
89 private Dictionary <object, string> _instancesByValueCache = null; // instance - name
90 private ContextStack _contextStack = null;
93 public bool RecycleInstances {
94 get { return _recycleInstances; }
96 VerifyNotInSession ();
97 _recycleInstances = value;
101 public bool PreserveNames {
102 get { return _preserveNames; }
104 VerifyNotInSession ();
105 _preserveNames = value;
109 public bool ValidateRecycledTypes {
110 get { return _validateRecycledTypes; }
112 VerifyNotInSession ();
113 _validateRecycledTypes = value;
117 public IContainer Container {
119 if (_designerContainer == null) {
120 _designerContainer = (this.GetService (typeof (IDesignerHost)) as IDesignerHost).Container;
122 return _designerContainer;
125 VerifyNotInSession ();
126 _designerContainer = value;
130 public object PropertyProvider {
131 get { return _propertyProvider; }
132 set { _propertyProvider = value; }
135 public IList Errors {
136 get { return _errors; }
139 public event EventHandler SessionDisposed;
140 public event EventHandler SessionCreated;
142 protected virtual void OnSessionCreated (EventArgs e)
144 if (SessionCreated != null) {
145 SessionCreated (this, e);
149 // For behaviour description:
151 // http://msdn2.microsoft.com/en-us/library/system.componentmodel.design.serialization.designerserializationmanager.validaterecycledtypes.aspx
152 // http://msdn2.microsoft.com/en-us/library/system.componentmodel.design.serialization.designerserializationmanager.preservenames.aspx
154 protected virtual object CreateInstance (Type type, ICollection arguments, string name, bool addToContainer)
158 object instance = null;
160 if (name != null && _recycleInstances) {
161 _instancesByNameCache.TryGetValue (name, out instance);
162 if (instance != null && _validateRecycledTypes) {
163 if (instance.GetType () != type)
168 if (instance == null || !_recycleInstances) {
169 instance = this.CreateInstance (type, arguments);
172 if (addToContainer && instance != null && this.Container != null && typeof (IComponent).IsAssignableFrom (type)) {
173 if (_preserveNames) {
174 this.Container.Add ((IComponent) instance, name);
177 if (name != null && this.Container.Components[name] != null) {
178 this.Container.Add ((IComponent) instance);
181 this.Container.Add ((IComponent) instance, name);
184 ISite site = ((IComponent)instance).Site; // get the name from the site in case a name has been generated.
189 if (instance != null && name != null) {
190 _instancesByNameCache[name] = instance;
191 _instancesByValueCache[instance] = name;
197 // Invokes the constructor that matches the arguments
199 private object CreateInstance (Type type, ICollection argsCollection)
201 object instance = null;
202 object[] arguments = null;
203 Type[] types = new Type[0];
205 if (argsCollection != null) {
206 arguments = new object[argsCollection.Count];
207 types = new Type[argsCollection.Count];
208 argsCollection.CopyTo (arguments, 0);
210 for (int i=0; i < arguments.Length; i++) {
211 if (arguments[i] == null)
214 types[i] = arguments[i].GetType ();
218 ConstructorInfo ctor = type.GetConstructor (types);
220 instance = ctor.Invoke (arguments);
226 public object GetSerializer (Type componentType, Type serializerType)
230 if (serializerType == null)
231 throw new ArgumentNullException ("serializerType");
233 object serializer = null;
235 if (componentType != null) {
238 _serializersCache.TryGetValue (componentType, out serializer);
240 // check for provider attribute and add it to the list of providers
242 if (serializer != null && !serializerType.IsAssignableFrom (serializer.GetType ()))
245 AttributeCollection attributes = TypeDescriptor.GetAttributes (componentType);
246 DefaultSerializationProviderAttribute providerAttribute = attributes[typeof (DefaultSerializationProviderAttribute)]
247 as DefaultSerializationProviderAttribute;
248 if (providerAttribute != null && this.GetType (providerAttribute.ProviderTypeName) == serializerType) {
250 object provider = Activator.CreateInstance (this.GetType (providerAttribute.ProviderTypeName),
251 BindingFlags.CreateInstance | BindingFlags.Public | BindingFlags.NonPublic,
254 ((IDesignerSerializationManager)this).AddSerializationProvider ((IDesignerSerializationProvider) provider);
258 // try 2: from provider
260 if (serializer == null) {
261 foreach (IDesignerSerializationProvider provider in _serializationProviders) {
262 serializer = provider.GetSerializer (this, null, componentType, serializerType);
263 if (serializer != null)
268 if (componentType != null) {
271 if (serializer == null) {
272 AttributeCollection attributes = TypeDescriptor.GetAttributes (componentType);
273 DesignerSerializerAttribute serializerAttribute = attributes[typeof (DesignerSerializerAttribute)] as DesignerSerializerAttribute;
274 if (serializerAttribute != null && this.GetType (serializerAttribute.SerializerTypeName) == serializerType) {
275 serializer = Activator.CreateInstance (this.GetType (serializerAttribute.SerializerTypeName),
276 BindingFlags.CreateInstance | BindingFlags.Public | BindingFlags.NonPublic,
281 if (serializer != null)
282 _serializersCache[componentType] = serializer;
288 private void VerifyInSession ()
290 if (_session == null)
291 throw new InvalidOperationException ("Not in session.");
294 private void VerifyNotInSession ()
296 if (_session != null)
297 throw new InvalidOperationException ("In session.");
300 public IDisposable CreateSession ()
302 _errors = new ArrayList ();
303 _session = new Session (this);
304 _serializersCache = new Dictionary<System.Type,object> ();
305 _instancesByNameCache = new Dictionary<string,object> ();
306 _instancesByValueCache = new Dictionary<object, string> ();
307 _contextStack = new ContextStack ();
309 this.OnSessionCreated (EventArgs.Empty);
314 protected virtual void OnSessionDisposed (EventArgs e)
318 _serializersCache.Clear ();
319 _serializersCache = null;
320 _instancesByNameCache.Clear ();
321 _instancesByNameCache = null;
322 _instancesByValueCache.Clear ();
323 _instancesByValueCache = null;
325 _contextStack = null;
326 _resolveNameHandler = null;
327 _serializationCompleteHandler = null;
329 if (SessionDisposed != null) {
330 SessionDisposed (this, e);
333 if (_serializationCompleteHandler != null)
334 _serializationCompleteHandler (this, EventArgs.Empty);
337 protected virtual Type GetType (string name)
340 throw new ArgumentNullException ("name");
342 this.VerifyInSession ();
345 ITypeResolutionService typeResSvc = this.GetService (typeof (ITypeResolutionService)) as ITypeResolutionService;
346 if (typeResSvc != null)
347 result = typeResSvc.GetType (name);
349 result = Type.GetType (name);
354 #region IDesignerSerializationManager implementation
356 protected virtual void OnResolveName (ResolveNameEventArgs e)
358 if (_resolveNameHandler != null) {
359 _resolveNameHandler (this, e);
363 void IDesignerSerializationManager.AddSerializationProvider (IDesignerSerializationProvider provider)
365 if (_serializationProviders == null)
366 _serializationProviders = new List <IDesignerSerializationProvider> ();
368 if (!_serializationProviders.Contains (provider))
369 _serializationProviders.Add (provider);
372 void IDesignerSerializationManager.RemoveSerializationProvider (IDesignerSerializationProvider provider)
374 if (_serializationProviders != null)
375 _serializationProviders.Remove (provider);
378 object IDesignerSerializationManager.CreateInstance (Type type, ICollection arguments, string name, bool addToContainer)
380 return this.CreateInstance (type, arguments, name, addToContainer);
383 object IDesignerSerializationManager.GetInstance (string name)
386 throw new ArgumentNullException ("name");
387 this.VerifyInSession ();
389 object instance = null;
390 _instancesByNameCache.TryGetValue (name, out instance);
392 if (instance == null && _preserveNames && this.Container != null)
393 instance = this.Container.Components[name];
395 if (instance == null)
396 instance = this.RequestInstance (name);
401 private object RequestInstance (string name)
403 ResolveNameEventArgs args = new ResolveNameEventArgs (name);
404 this.OnResolveName (args);
408 Type IDesignerSerializationManager.GetType (string name)
410 return this.GetType (name);
413 object IDesignerSerializationManager.GetSerializer (Type type, Type serializerType)
415 return this.GetSerializer (type, serializerType);
418 string IDesignerSerializationManager.GetName (object instance)
420 if (instance == null)
421 throw new ArgumentNullException ("instance");
422 this.VerifyInSession ();
425 if (instance is IComponent) {
426 ISite site = ((IComponent)instance).Site;
427 if (site != null && site is INestedSite)
428 name = ((INestedSite)site).FullName;
429 else if (site != null)
433 _instancesByValueCache.TryGetValue (instance, out name);
437 void IDesignerSerializationManager.SetName (object instance, string name)
439 if (instance == null)
440 throw new ArgumentNullException ("instance");
442 throw new ArgumentNullException ("name");
444 if (_instancesByNameCache.ContainsKey (name))
445 throw new ArgumentException ("The object specified by instance already has a name, or name is already used by another named object.");
447 _instancesByNameCache.Add (name, instance);
448 _instancesByValueCache.Add (instance, name);
451 void IDesignerSerializationManager.ReportError (object error)
453 this.VerifyInSession ();
457 ContextStack IDesignerSerializationManager.Context {
458 get { return _contextStack; }
461 PropertyDescriptorCollection IDesignerSerializationManager.Properties {
463 PropertyDescriptorCollection properties = new PropertyDescriptorCollection (new PropertyDescriptor[0]);
464 object component = this.PropertyProvider;
465 if (component != null)
466 properties = TypeDescriptor.GetProperties (component);
472 private EventHandler _serializationCompleteHandler;
473 private ResolveNameEventHandler _resolveNameHandler;
475 event EventHandler IDesignerSerializationManager.SerializationComplete {
477 this.VerifyInSession ();
478 _serializationCompleteHandler = (EventHandler) Delegate.Combine (_serializationCompleteHandler, value);
481 _serializationCompleteHandler = (EventHandler) Delegate.Remove (_serializationCompleteHandler, value);
485 event ResolveNameEventHandler IDesignerSerializationManager.ResolveName {
487 this.VerifyInSession ();
488 _resolveNameHandler = (ResolveNameEventHandler) Delegate.Combine (_resolveNameHandler, value);
491 _resolveNameHandler = (ResolveNameEventHandler) Delegate.Remove (_resolveNameHandler, value);
496 object IServiceProvider.GetService (Type service)
498 return this.GetService (service);
501 protected virtual object GetService (Type service)
503 object result = null;
504 if (_serviceProvider != null)
505 result = _serviceProvider.GetService (service);