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
)
157 object instance
= null;
159 if (name
!= null && _recycleInstances
) {
160 _instancesByNameCache
.TryGetValue (name
, out instance
);
161 if (instance
!= null && _validateRecycledTypes
) {
162 if (instance
.GetType () != type
)
167 if (instance
== null || !_recycleInstances
)
168 instance
= this.CreateInstance (type
, arguments
);
170 if (addToContainer
&& instance
!= null && this.Container
!= null && typeof (IComponent
).IsAssignableFrom (type
)) {
171 if (_preserveNames
) {
172 this.Container
.Add ((IComponent
) instance
, name
);
175 if (name
!= null && this.Container
.Components
[name
] != null) {
176 this.Container
.Add ((IComponent
) instance
);
179 this.Container
.Add ((IComponent
) instance
, name
);
182 ISite site
= ((IComponent
)instance
).Site
; // get the name from the site in case a name has been generated.
187 if (instance
!= null && name
!= null) {
188 _instancesByNameCache
[name
] = instance
;
189 _instancesByValueCache
[instance
] = name
;
195 // Invokes the constructor that matches the arguments
197 private object CreateInstance (Type type
, ICollection argsCollection
)
199 object instance
= null;
200 object[] arguments
= null;
201 Type
[] types
= new Type
[0];
203 if (argsCollection
!= null) {
204 arguments
= new object[argsCollection
.Count
];
205 types
= new Type
[argsCollection
.Count
];
206 argsCollection
.CopyTo (arguments
, 0);
208 for (int i
=0; i
< arguments
.Length
; i
++) {
209 if (arguments
[i
] == null)
212 types
[i
] = arguments
[i
].GetType ();
216 ConstructorInfo ctor
= type
.GetConstructor (types
);
218 instance
= ctor
.Invoke (arguments
);
224 public object GetSerializer (Type componentType
, Type serializerType
)
228 if (serializerType
== null)
229 throw new ArgumentNullException ("serializerType");
231 object serializer
= null;
233 if (componentType
!= null) {
236 _serializersCache
.TryGetValue (componentType
, out serializer
);
238 // check for provider attribute and add it to the list of providers
240 if (serializer
!= null && !serializerType
.IsAssignableFrom (serializer
.GetType ()))
243 AttributeCollection attributes
= TypeDescriptor
.GetAttributes (componentType
);
244 DefaultSerializationProviderAttribute providerAttribute
= attributes
[typeof (DefaultSerializationProviderAttribute
)]
245 as DefaultSerializationProviderAttribute
;
246 if (providerAttribute
!= null && this.GetType (providerAttribute
.ProviderTypeName
) == serializerType
) {
247 object provider
= Activator
.CreateInstance (this.GetType (providerAttribute
.ProviderTypeName
),
248 BindingFlags
.CreateInstance
| BindingFlags
.Public
| BindingFlags
.NonPublic
,
250 ((IDesignerSerializationManager
)this).AddSerializationProvider ((IDesignerSerializationProvider
) provider
);
254 // try 2: DesignerSerializerAttribute
256 if (serializer
== null && componentType
!= null) {
257 AttributeCollection attributes
= TypeDescriptor
.GetAttributes (componentType
);
258 DesignerSerializerAttribute serializerAttribute
= attributes
[typeof (DesignerSerializerAttribute
)] as DesignerSerializerAttribute
;
259 if (serializerAttribute
!= null &&
260 this.GetType (serializerAttribute
.SerializerBaseTypeName
) == serializerType
) {
262 serializer
= Activator
.CreateInstance (this.GetType (serializerAttribute
.SerializerTypeName
),
263 BindingFlags
.CreateInstance
| BindingFlags
.Instance
|
264 BindingFlags
.Public
| BindingFlags
.NonPublic
,
269 if (serializer
!= null)
270 _serializersCache
[componentType
] = serializer
;
273 // try 3: from provider
275 if (serializer
== null && _serializationProviders
!= null) {
276 foreach (IDesignerSerializationProvider provider
in _serializationProviders
) {
277 serializer
= provider
.GetSerializer (this, null, componentType
, serializerType
);
278 if (serializer
!= null)
286 private void VerifyInSession ()
288 if (_session
== null)
289 throw new InvalidOperationException ("Not in session.");
292 private void VerifyNotInSession ()
294 if (_session
!= null)
295 throw new InvalidOperationException ("In session.");
298 public IDisposable
CreateSession ()
300 VerifyNotInSession ();
301 _errors
= new ArrayList ();
302 _session
= new Session (this);
303 _serializersCache
= new Dictionary
<System
.Type
,object> ();
304 _instancesByNameCache
= new Dictionary
<string,object> ();
305 _instancesByValueCache
= new Dictionary
<object, string> ();
306 _contextStack
= new ContextStack ();
308 this.OnSessionCreated (EventArgs
.Empty
);
313 protected virtual void OnSessionDisposed (EventArgs e
)
317 _serializersCache
.Clear ();
318 _serializersCache
= null;
319 _instancesByNameCache
.Clear ();
320 _instancesByNameCache
= null;
321 _instancesByValueCache
.Clear ();
322 _instancesByValueCache
= null;
324 _contextStack
= null;
325 _resolveNameHandler
= null;
326 _serializationCompleteHandler
= null;
328 if (SessionDisposed
!= null) {
329 SessionDisposed (this, e
);
332 if (_serializationCompleteHandler
!= null)
333 _serializationCompleteHandler (this, EventArgs
.Empty
);
336 protected virtual Type
GetType (string name
)
339 throw new ArgumentNullException ("name");
341 this.VerifyInSession ();
344 ITypeResolutionService typeResSvc
= this.GetService (typeof (ITypeResolutionService
)) as ITypeResolutionService
;
345 if (typeResSvc
!= null)
346 result
= typeResSvc
.GetType (name
);
348 result
= Type
.GetType (name
);
353 #region IDesignerSerializationManager implementation
355 protected virtual void OnResolveName (ResolveNameEventArgs e
)
357 if (_resolveNameHandler
!= null) {
358 _resolveNameHandler (this, e
);
362 void IDesignerSerializationManager
.AddSerializationProvider (IDesignerSerializationProvider provider
)
364 if (_serializationProviders
== null)
365 _serializationProviders
= new List
<IDesignerSerializationProvider
> ();
367 if (!_serializationProviders
.Contains (provider
))
368 _serializationProviders
.Add (provider
);
371 void IDesignerSerializationManager
.RemoveSerializationProvider (IDesignerSerializationProvider provider
)
373 if (_serializationProviders
!= null)
374 _serializationProviders
.Remove (provider
);
377 object IDesignerSerializationManager
.CreateInstance (Type type
, ICollection arguments
, string name
, bool addToContainer
)
379 return this.CreateInstance (type
, arguments
, name
, addToContainer
);
382 object IDesignerSerializationManager
.GetInstance (string name
)
385 throw new ArgumentNullException ("name");
386 this.VerifyInSession ();
388 object instance
= null;
389 _instancesByNameCache
.TryGetValue (name
, out instance
);
391 if (instance
== null && this.Container
!= null)
392 instance
= this.Container
.Components
[name
];
394 if (instance
== null)
395 instance
= this.RequestInstance (name
);
400 private object RequestInstance (string name
)
402 ResolveNameEventArgs args
= new ResolveNameEventArgs (name
);
403 this.OnResolveName (args
);
407 Type IDesignerSerializationManager
.GetType (string name
)
409 return this.GetType (name
);
412 object IDesignerSerializationManager
.GetSerializer (Type type
, Type serializerType
)
414 return this.GetSerializer (type
, serializerType
);
417 string IDesignerSerializationManager
.GetName (object instance
)
419 if (instance
== null)
420 throw new ArgumentNullException ("instance");
421 this.VerifyInSession ();
424 if (instance
is IComponent
) {
425 ISite site
= ((IComponent
)instance
).Site
;
426 if (site
!= null && site
is INestedSite
)
427 name
= ((INestedSite
)site
).FullName
;
428 else if (site
!= null)
432 _instancesByValueCache
.TryGetValue (instance
, out name
);
436 void IDesignerSerializationManager
.SetName (object instance
, string name
)
438 if (instance
== null)
439 throw new ArgumentNullException ("instance");
441 throw new ArgumentNullException ("name");
443 if (_instancesByNameCache
.ContainsKey (name
))
444 throw new ArgumentException ("The object specified by instance already has a name, or name is already used by another named object.");
446 _instancesByNameCache
.Add (name
, instance
);
447 _instancesByValueCache
.Add (instance
, name
);
450 void IDesignerSerializationManager
.ReportError (object error
)
452 this.VerifyInSession ();
456 ContextStack IDesignerSerializationManager
.Context
{
457 get { return _contextStack; }
460 PropertyDescriptorCollection IDesignerSerializationManager
.Properties
{
462 PropertyDescriptorCollection properties
= new PropertyDescriptorCollection (new PropertyDescriptor
[0]);
463 object component
= this.PropertyProvider
;
464 if (component
!= null)
465 properties
= TypeDescriptor
.GetProperties (component
);
471 private EventHandler _serializationCompleteHandler
;
472 private ResolveNameEventHandler _resolveNameHandler
;
474 event EventHandler IDesignerSerializationManager
.SerializationComplete
{
476 this.VerifyInSession ();
477 _serializationCompleteHandler
= (EventHandler
) Delegate
.Combine (_serializationCompleteHandler
, value);
480 _serializationCompleteHandler
= (EventHandler
) Delegate
.Remove (_serializationCompleteHandler
, value);
484 event ResolveNameEventHandler IDesignerSerializationManager
.ResolveName
{
486 this.VerifyInSession ();
487 _resolveNameHandler
= (ResolveNameEventHandler
) Delegate
.Combine (_resolveNameHandler
, value);
490 _resolveNameHandler
= (ResolveNameEventHandler
) Delegate
.Remove (_resolveNameHandler
, value);
495 object IServiceProvider
.GetService (Type service
)
497 return this.GetService (service
);
500 protected virtual object GetService (Type service
)
502 object result
= null;
503 if (_serviceProvider
!= null)
504 result
= _serviceProvider
.GetService (service
);