Code:
/ FX-1434 / FX-1434 / 1.0 / untmp / whidbey / REDBITS / ndp / fx / src / Designer / Host / Serialization / DesignerSerializationManager.cs / 1 / DesignerSerializationManager.cs
//------------------------------------------------------------------------------ //// Copyright (c) Microsoft Corporation. All rights reserved. // //----------------------------------------------------------------------------- namespace System.ComponentModel.Design.Serialization { using System; using System.Collections; using System.Collections.Specialized; using System.ComponentModel; using System.ComponentModel.Design; using System.ComponentModel.Design.Serialization; using System.Design; using System.Diagnostics; using System.IO; using System.Reflection; using System.Runtime.InteropServices; using System.Runtime.Serialization; using System.Text; ////// /// This object is a complete implementation of IDesignerSerializationManager. It can be used to /// begin the serialization / deserialization process for any serialization scheme that utilizes /// IDesignerSerializationManager. /// public class DesignerSerializationManager : IDesignerSerializationManager { private IServiceProvider provider; private ITypeResolutionService typeResolver; private bool searchedTypeResolver; private bool recycleInstances; private bool validateRecycledTypes; private bool preserveNames; private IContainer container; private IDisposable session; private ResolveNameEventHandler resolveNameEventHandler; private EventHandler serializationCompleteEventHandler; private EventHandler sessionCreatedEventHandler; private EventHandler sessionDisposedEventHandler; private ArrayList designerSerializationProviders; private Hashtable defaultProviderTable; private Hashtable instancesByName; private Hashtable namesByInstance; private Hashtable serializers; private ArrayList errorList; private ContextStack contextStack; private PropertyDescriptorCollection properties; private object propertyProvider; ////// /// Creates a new serialization manager. /// public DesignerSerializationManager() { this.preserveNames = true; this.validateRecycledTypes = true; } ////// /// Creates a new serialization manager. /// public DesignerSerializationManager(IServiceProvider provider) { if (provider == null) { throw new ArgumentNullException("provider"); } this.provider = provider; this.preserveNames = true; this.validateRecycledTypes = true; } ////// /// Provides access to the container that components will /// be added to. The default implementation searches /// for IDesignerHost in the service provider and uses /// its container if it exists. /// public IContainer Container { get { if (container == null) { IDesignerHost host = GetService(typeof(IDesignerHost)) as IDesignerHost; if (host != null) { container = host.Container; } } return container; } set { CheckNoSession(); container = value; } } ////// /// This retrieves the collection of errors that have /// been reported to the serialization manager. /// Additionaly, new errors can be added to the list /// by accessing this property. /// public IList Errors { get { CheckSession(); if (errorList == null) { errorList = new ArrayList(); } return errorList; } } ////// /// This property determines the behavior of the CreateInstance method. If true, CreateInstance will /// pass the given component name. If false, CreateInstance will check for the presence /// of the given name in the container. If it does not exist, it will use the given name. /// If it does exist, it will pass a null value as the name of a component when adding /// it to the container, thereby giving it a new name. /// This second variation is useful for implementing a serializer that always duplicates objects, rather than /// assuming those objects do not exist. Paste commands often use this type of serializer. /// The default value of this property is true. /// public bool PreserveNames { get { return preserveNames; } set { CheckNoSession(); preserveNames = value; } } ////// /// This property returns the object that should be used to provide properties to the serialization manager's Propeties property. This object's /// public properties will be inspected and wrapped in new property descriptors that have a target object of the serialization manager. /// public object PropertyProvider { get { return propertyProvider; } set { if (propertyProvider != value) { propertyProvider = value; properties = null; } } } ////// /// This property determines the behavior of the CreateInstance method. If false, CreateInstance will always create a new instance /// of an object. If true, CreateInstance will first search the nametable and container for an object of the same name. If such /// an object exists and is of the same type, CreateInstance will return the existing object instance. This second variation is /// useful for implemeting a serializer that applies serialization state to an existing set of objects, rather than always creating /// a new tree. Undo often uses this type of serializer. /// The default value of this property is false. /// public bool RecycleInstances { get { return recycleInstances; } set { CheckNoSession(); recycleInstances = value; } } ////// /// This property determines the behavior of the CreateInstance method and only applies if RecyleInstances is true. If true, and /// an existing instance is found for the given name, it will only be returned if the two types match. If false, the instance /// will be returned even if the two types do not match. This is useful for "morphing" one type of object to another if they have /// similar properties but share no common parent or interface. /// The default value of this property is true. /// public bool ValidateRecycledTypes { get { return validateRecycledTypes; } set { CheckNoSession(); validateRecycledTypes = value; } } ////// /// Event that is raised when a session is created. /// public event EventHandler SessionCreated { add { sessionCreatedEventHandler += value; } remove { sessionCreatedEventHandler -= value; } } ////// /// Event that is raised when a session is disposed. /// public event EventHandler SessionDisposed { add { sessionDisposedEventHandler += value; } remove { sessionDisposedEventHandler -= value; } } ////// Used to verify that no session is active. If there is, this method /// throws. /// private void CheckNoSession() { if (session != null) { throw new InvalidOperationException(SR.GetString(SR.SerializationManagerWithinSession)); } } ////// Used to verify that there is an open session. If there isn't, this method /// throws. /// private void CheckSession() { if (session == null) { throw new InvalidOperationException(SR.GetString(SR.SerializationManagerNoSession)); } } ////// /// Creates an instance of the specified type. The default /// implementation will create the object. If the object implements /// IComponent and only requires an empty or IContainer style /// constructor, this will search for IDesignerHost and create /// through the host. Otherwise it will use reflection. If /// addToContainer is true, this will add to the container /// using this class's Conainer property, using the /// name provided if it is not null. /// protected virtual object CreateInstance(Type type, ICollection arguments, string name, bool addToContainer) { object[] argArray = null; if (arguments != null && arguments.Count > 0) { argArray = new object[arguments.Count]; arguments.CopyTo(argArray, 0); } object instance = null; // If we have been asked to recycle instances, look in our nametable // and container first for an object matching this name and type. If // we find it, we will use it. // if (RecycleInstances && name != null) { if (instancesByName != null) { instance = instancesByName[name]; } if (instance == null && addToContainer && Container != null) { instance = Container.Components[name]; } if (instance != null && ValidateRecycledTypes && instance.GetType() != type) { // We got an instance, but it is not of the correct type. We // don't allow this. instance = null; } } // If the stars properly align, we will let the designer host create the component. // For this to happen, the following criteria must hold true: // // 1. The type must be a component. // 2. addToContainer is true. // 3. The type has a null ctor or an IContainer ctor. // 4. The host is available and its container matches our container. // // The reason for this is that if we went through activator, // and if the object already specified a constructor that took an IContainer, our // deserialization mechanism would equate the container to the designer host. This // is the correct thing to do, but it has the side effect of adding the compnent // to the designer host twice -- once with a default name, and a second time with // the name we provide. This equates to a component rename, which isn't cheap, // so we don't want to do it when we load each and every component. // if (instance == null && addToContainer && typeof(IComponent).IsAssignableFrom(type) && (argArray == null || argArray.Length == 0 ||( argArray.Length == 1 && argArray[0] == Container))) { IDesignerHost host = GetService(typeof(IDesignerHost)) as IDesignerHost; if (host != null && host.Container == Container) { bool ignoreName = false; if (!PreserveNames && name != null) { // Check if this name exists in the container. If so, // don't use it. // if (Container.Components[name] != null) { ignoreName = true; } } if (name == null || ignoreName) { instance = host.CreateComponent(type); } else { instance = host.CreateComponent(type, name); } } } // Default case, just create the component through reflection. // if (instance == null) { try { try { // First, just try to create the object directly with the arguments. generaly this // should work. // instance = TypeDescriptor.CreateInstance(provider, type, null, argArray); } catch (MissingMethodException mmex) { // okay, the create failed because the argArray didn't match the types of ctors that // are available. don't panic, we're tough. we'll try to coerce the types to match // the ctor. // Type[] types = new Type[argArray.Length]; // first, get the types of the arguments we've got. // for(int index = 0; index < argArray.Length; index++) { if (argArray[index] != null) { types[index] = argArray[index].GetType(); } } object[] tempArgs = new object[argArray.Length]; // now, walk the public ctors looking for one to // invoke here with the arguments we have. // foreach(ConstructorInfo ci in TypeDescriptor.GetReflectionType(type).GetConstructors(BindingFlags.Instance | BindingFlags.Public | BindingFlags.CreateInstance)) { ParameterInfo[] pi = ci.GetParameters(); // obviously the count has to match // if (pi != null && pi.Length == types.Length) { bool match = true; // now walk every type of argument and compare it to // the corresponding argument. if it matches up exactly or is a derived type, great. // otherwise, we'll try to use IConvertible to make it into the right thing. // for (int t = 0; t < types.Length; t++) { if (types[t] == null || pi[t].ParameterType.IsAssignableFrom(types[t])) { tempArgs[t] = argArray[t]; continue; } if (argArray[t] is IConvertible) { try { // try the IConvertible route. If it works, we'll call it a match // for this parameter and continue on. // tempArgs[t] = ((IConvertible)argArray[t]).ToType(pi[t].ParameterType, null); continue; } catch (InvalidCastException) { } } match = false; break; } // all of the parameters were converted or matched, so try the creation again. // if that works, we're in the money. // if (match) { instance = TypeDescriptor.CreateInstance(provider, type, null, tempArgs); break; } } } // we still failed...rethrow the original exception. // if (instance == null) { throw mmex; } } } catch(MissingMethodException) { StringBuilder argTypes = new StringBuilder(); foreach (object o in argArray) { if (argTypes.Length > 0) { argTypes.Append(", "); } if (o != null) { argTypes.Append(o.GetType().Name); } else { argTypes.Append("null"); } } Exception ex = new SerializationException(SR.GetString(SR.SerializationManagerNoMatchingCtor, type.FullName, argTypes.ToString())); ex.HelpLink = SR.SerializationManagerNoMatchingCtor; throw ex; } // Now, if we needed to add this to the container, do so . // if (addToContainer && instance is IComponent && Container != null) { bool ignoreName = false; if (!PreserveNames && name != null) { // Check if this name exists in the container. If so, // don't use it. // if (Container.Components[name] != null) { ignoreName = true; } } if (name == null || ignoreName) { Container.Add((IComponent)instance); } else { Container.Add((IComponent)instance, name); } } } return instance; } ////// /// Creates a new serialization session. Most data within /// the serialization manager is transient and only lives /// for the life of a serialization session. When a session /// is disposed, serialization is considered to be complete /// and this transient state is cleared. This allows a /// single instance of a serialization manager to be used /// to serialize multiple object trees. Some state, including /// the service provider and any custom serialization providers /// that were added to the serialization manager, span sessions. /// public IDisposable CreateSession() { if (session != null) { throw new InvalidOperationException(SR.GetString(SR.SerializationManagerAreadyInSession)); } session = new SerializationSession(this); OnSessionCreated(EventArgs.Empty); return session; } ////// /// This retrieves the serializer for the given object type. /// You can request what type of serializer you would like. /// It is possible for this method to return null if there /// is no serializer of the requested type. /// public object GetSerializer(Type objectType, Type serializerType) { if (serializerType == null) { throw new ArgumentNullException("serializerType"); } object serializer = null; if (objectType != null) { if (serializers != null) { // I don't double hash here. It will be a very rare day where // multiple types of serializers will be used in the same scheme. // We still handle it, but we just don't cache. // serializer = serializers[objectType]; if (serializer != null && !serializerType.IsAssignableFrom(serializer.GetType())) { serializer = null; } } // Now actually look in the type's metadata. // if (serializer == null) { AttributeCollection attributes = TypeDescriptor.GetAttributes(objectType); foreach(Attribute attr in attributes) { if (attr is DesignerSerializerAttribute) { DesignerSerializerAttribute da = (DesignerSerializerAttribute)attr; string typeName = da.SerializerBaseTypeName; // This serializer must support the correct base type or we're not interested. // if (typeName != null) { Type baseType = GetType(typeName); if (baseType == serializerType && da.SerializerTypeName != null && da.SerializerTypeName.Length > 0) { Type type = GetType(da.SerializerTypeName); Debug.Assert(type != null, "Type " + objectType.FullName + " has a serializer that we couldn't bind to: " + da.SerializerTypeName); if (type != null) { serializer = Activator.CreateInstance(type, BindingFlags.Instance | BindingFlags.Public | BindingFlags.NonPublic | BindingFlags.CreateInstance, null, null, null); break; } } } } } // And stash this little guy for later, but only if we're in a session. // If we're outside of a session this should still be useable for resolving // serializers, but we don't cache them. // if (serializer != null && session != null) { if (serializers == null) { serializers = new Hashtable(); } serializers[objectType] = serializer; } } } // Check for a default serialization provider // if (defaultProviderTable == null || !defaultProviderTable.ContainsKey(serializerType)) { Type defaultSerializerType = null; DefaultSerializationProviderAttribute a = (DefaultSerializationProviderAttribute)TypeDescriptor.GetAttributes(serializerType)[typeof(DefaultSerializationProviderAttribute)]; if (a != null) { defaultSerializerType = GetType(a.ProviderTypeName); if (defaultSerializerType != null && typeof(IDesignerSerializationProvider).IsAssignableFrom(defaultSerializerType)) { IDesignerSerializationProvider p = (IDesignerSerializationProvider)Activator.CreateInstance( defaultSerializerType, BindingFlags.Instance | BindingFlags.Public | BindingFlags.NonPublic | BindingFlags.CreateInstance, null, null, null); ((IDesignerSerializationManager)this).AddSerializationProvider(p); } } if (defaultProviderTable == null) { defaultProviderTable = new Hashtable(); } defaultProviderTable[serializerType] = defaultSerializerType; } // Designer serialization providers can override our metadata discovery. // We loop until we reach steady state. This breaks order dependencies // by allowing all providers a chance to party on each other's serializers. // if (designerSerializationProviders != null) { bool continueLoop = true; for(int i = 0; continueLoop && i < designerSerializationProviders.Count; i++) { continueLoop = false; foreach(IDesignerSerializationProvider provider in designerSerializationProviders) { object newSerializer = provider.GetSerializer(this, serializer, objectType, serializerType); if (newSerializer != null) { continueLoop = (serializer != newSerializer); serializer = newSerializer; } } } } return serializer; } ////// /// Provides access to the underlying IServiceProvider /// protected virtual object GetService(Type serviceType) { if (serviceType == typeof(IContainer)) { return Container; } if (provider != null) { return provider.GetService(serviceType); } return null; } ////// /// Retrives the type for the given name using the type resolution /// service, if available. /// protected virtual Type GetType(string typeName) { if (typeResolver == null && !searchedTypeResolver) { typeResolver = GetService(typeof(ITypeResolutionService)) as ITypeResolutionService; searchedTypeResolver = true; } if (typeResolver == null) { return Type.GetType(typeName); } else { return typeResolver.GetType(typeName); } } ////// /// Event that is raised when a name needs to be resolved to an object instance.. /// protected virtual void OnResolveName(ResolveNameEventArgs e) { if (resolveNameEventHandler != null) { resolveNameEventHandler(this, e); } } ////// /// Event that is raised when a session is created. /// protected virtual void OnSessionCreated(EventArgs e) { if (sessionCreatedEventHandler != null) { sessionCreatedEventHandler(this, e); } } ////// /// Event that is raised when a session is disposed. /// protected virtual void OnSessionDisposed(EventArgs e) { try { try { if (sessionDisposedEventHandler != null) { sessionDisposedEventHandler(this, e); } } finally { if (serializationCompleteEventHandler != null) { serializationCompleteEventHandler(this, EventArgs.Empty); } } } finally { resolveNameEventHandler = null; serializationCompleteEventHandler = null; instancesByName = null; namesByInstance = null; serializers = null; contextStack = null; errorList = null; session = null; } } ////// /// This method takes a property that is owned by the /// given owner, and it wraps them in new property that /// is owned by the serialization manager. /// private PropertyDescriptor WrapProperty(PropertyDescriptor property, object owner) { if (property == null) { throw new ArgumentNullException("property"); } // owner can be null for static properties. return new WrappedPropertyDescriptor(property, owner); } ////// /// The Context property provides a user-defined storage area /// implemented as a stack. This storage area is a useful way /// to provide communication across serializers, as serialization /// is a generally hierarchial process. /// ContextStack IDesignerSerializationManager.Context { get { if (contextStack == null) { CheckSession(); contextStack = new ContextStack(); } return contextStack; } } ////// /// The Properties property provides a set of custom properties /// the serialization manager may surface. The set of properties /// exposed here is defined by the implementor of /// IDesignerSerializationManager. /// PropertyDescriptorCollection IDesignerSerializationManager.Properties { get { if (properties == null) { object propObject = PropertyProvider; PropertyDescriptor[] propArray; if (propObject == null) { propArray = new PropertyDescriptor[0]; } else { PropertyDescriptorCollection props = TypeDescriptor.GetProperties(propObject); propArray = new PropertyDescriptor[props.Count]; for (int i = 0; i < propArray.Length; i++) { propArray[i] = WrapProperty(props[i], propObject); } } properties = new PropertyDescriptorCollection(propArray); } return properties; } } ////// /// ResolveName event. This event /// is raised when GetName is called, but the name is not found /// in the serialization manager's name table. It provides a /// way for a serializer to demand-create an object so the serializer /// does not have to order object creation by dependency. This /// delegate is cleared immediately after serialization or deserialization /// is complete. /// event ResolveNameEventHandler IDesignerSerializationManager.ResolveName { add { CheckSession(); resolveNameEventHandler += value; } remove { resolveNameEventHandler -= value; } } ////// /// This event is raised when serialization or deserialization /// has been completed. Generally, serialization code should /// be written to be stateless. Should some sort of state /// be necessary to maintain, a serializer can listen to /// this event to know when that state should be cleared. /// An example of this is if a serializer needs to write /// to another file, such as a resource file. In this case /// it would be inefficient to design the serializer /// to close the file when finished because serialization of /// an object graph generally requires several serializers. /// The resource file would be opened and closed many times. /// Instead, the resource file could be accessed through /// an object that listened to the SerializationComplete /// event, and that object could close the resource file /// at the end of serialization. /// event EventHandler IDesignerSerializationManager.SerializationComplete { add { CheckSession(); serializationCompleteEventHandler += value; } remove { serializationCompleteEventHandler -= value; } } ////// /// This method adds a custom serialization provider to the /// serialization manager. A custom serialization provider will /// get the opportunity to return a serializer for a data type /// before the serialization manager looks in the type's /// metadata. /// void IDesignerSerializationManager.AddSerializationProvider(IDesignerSerializationProvider provider) { if (designerSerializationProviders == null) { designerSerializationProviders = new ArrayList(); } if (!designerSerializationProviders.Contains(provider)) { designerSerializationProviders.Add(provider); } } ////// /// Creates an instance of the given type and adds it to a collection /// of named instances. Objects that implement IComponent will be /// added to the design time container if addToContainer is true. /// object IDesignerSerializationManager.CreateInstance(Type type, ICollection arguments, string name, bool addToContainer) { CheckSession(); // If we were given a name verify that the name doesn't // already exist. We do not verify uniqueness in our parent container // here because CreateInstance may modify the name for us. If it // didn't, the container itself will throw, so we're covered. // if (name != null) { if (instancesByName != null && instancesByName.ContainsKey(name)) { Exception ex = new SerializationException(SR.GetString(SR.SerializationManagerDuplicateComponentDecl, name)); ex.HelpLink = SR.SerializationManagerDuplicateComponentDecl; throw ex; } } object instance = CreateInstance(type, arguments, name, addToContainer); // If we have a name save it into our own nametable. We // do this even for objects that were added to the container, because // containers reserve the right to change the name in case of collision. // Changing the name is fine, but it would be very difficult to map // that to the rest of the serializers. Instead, we keep the old // name in our local nametable so a serializer can ask for an object // by the old name. Because the old nametable is searched first, the // old name is preserved. Note that this technique is ONLY valid // if RecycleInstances is false. If it is true, we cannot store // in the old nametable because it would be possible to fetch // the wrong value from the container. Consider a request for // "button1' that results in the creation of an object in the // container called "button2" due to a collision. If a request // later came in for "button2", the wrong object would be returned // because RecycleInstances checks the container first. So, it // is only safe to store the local value if RecycleInstances is false. // When RecycleInstances is true if there was a collision the object // would have been returned, so there is no need to store locally. // if (name != null // If we were given a name && (!(instance is IComponent) // And it's not an icomponent || !RecycleInstances)) { // Or it is an icomponent but recycle instances is turned off if (instancesByName == null) { instancesByName = new Hashtable(); namesByInstance = new Hashtable(new ReferenceComparer()); } instancesByName[name] = instance; namesByInstance[instance] = name; } return instance; } ////// /// Retrieves an instance of a created object of the given name, or /// null if that object does not exist. /// object IDesignerSerializationManager.GetInstance(string name) { object instance = null; if (name == null) { throw new ArgumentNullException("name"); } CheckSession(); // Check our local nametable first // if (instancesByName != null) { instance = instancesByName[name]; } if (instance == null && PreserveNames && Container != null) { instance = Container.Components[name]; } if (instance == null) { ResolveNameEventArgs e = new ResolveNameEventArgs(name); OnResolveName(e); instance = e.Value; } return instance; } ////// /// Retrieves a name for the specified object, or null if the object /// has no name. /// string IDesignerSerializationManager.GetName(object value) { string name = null; if (value == null) { throw new ArgumentNullException("value"); } CheckSession(); // Check our local nametable first // if (namesByInstance != null) { name = (string)namesByInstance[value]; } if (name == null && value is IComponent) { ISite site = ((IComponent)value).Site; if (site != null) { INestedSite nestedSite = site as INestedSite; if (nestedSite != null) { name = nestedSite.FullName; } else { name = site.Name; } } } return name; } ////// /// Retrieves a serializer of the requested type for the given /// object type. /// object IDesignerSerializationManager.GetSerializer(Type objectType, Type serializerType) { return GetSerializer(objectType, serializerType); } ////// /// Retrieves a type of the given name. /// Type IDesignerSerializationManager.GetType(string typeName) { CheckSession(); Type t = null; while (t == null) { t = GetType(typeName); if (t == null && typeName != null && typeName.Length > 0) { int dotIndex = typeName.LastIndexOf('.'); if (dotIndex == -1 || dotIndex == typeName.Length - 1) { break; } typeName = typeName.Substring(0, dotIndex) + "+" + typeName.Substring(dotIndex + 1, typeName.Length - dotIndex - 1); } } return t; } ////// /// Removes a previously added serialization provider. /// void IDesignerSerializationManager.RemoveSerializationProvider(IDesignerSerializationProvider provider) { if (designerSerializationProviders != null) { designerSerializationProviders.Remove(provider); } } ////// /// Reports a non-fatal error in serialization. The serialization /// manager may implement a logging scheme to alert the caller /// to all non-fatal errors at once. If it doesn't, it should /// immediately throw in this method, which should abort /// serialization. /// Serialization may continue after calling this function. /// void IDesignerSerializationManager.ReportError(object errorInformation) { CheckSession(); if (errorInformation != null) { Errors.Add(errorInformation); } } internal ArrayList SerializationProviders { get { return (designerSerializationProviders != null) ? designerSerializationProviders.Clone() as ArrayList : new ArrayList(); } } ////// /// Provides a way to set the name of an existing object. /// This is useful when it is necessary to create an /// instance of an object without going through CreateInstance. /// An exception will be thrown if you try to rename an existing /// object or if you try to give a new object a name that /// is already taken. /// void IDesignerSerializationManager.SetName(object instance, string name) { CheckSession(); if (instance == null) { throw new ArgumentNullException("instance"); } if (name == null) { throw new ArgumentNullException("name"); } if (instancesByName == null) { instancesByName = new Hashtable(); namesByInstance = new Hashtable(new ReferenceComparer()); } if (instancesByName[name] != null) { throw new ArgumentException(SR.GetString(SR.SerializationManagerNameInUse, name)); } if (namesByInstance[instance] != null) { throw new ArgumentException(SR.GetString(SR.SerializationManagerObjectHasName, name, (string)namesByInstance[instance])); } instancesByName[name] = instance; namesByInstance[instance] = name; } ////// /// IServiceProvider implementation. /// object IServiceProvider.GetService(Type serviceType) { return GetService(serviceType); } ////// Session object that implements IDisposable. /// private sealed class SerializationSession : IDisposable { private DesignerSerializationManager serializationManager; internal SerializationSession(DesignerSerializationManager serializationManager) { this.serializationManager = serializationManager; } public void Dispose() { serializationManager.OnSessionDisposed(EventArgs.Empty); } } ////// A key comparer that can be passed to a hash table /// to use object reference identity as the key comparision. /// private sealed class ReferenceComparer : IEqualityComparer { bool IEqualityComparer.Equals(object x, object y) { return object.ReferenceEquals(x, y); } int IEqualityComparer.GetHashCode(object x) { if (x != null) { return x.GetHashCode(); } return 0; } } ////// Wrapped property descriptor. Takes the given property /// and wraps it in a new one that can take the designer serialization /// manager as a target. /// private sealed class WrappedPropertyDescriptor : PropertyDescriptor { private object target; private PropertyDescriptor property; internal WrappedPropertyDescriptor(PropertyDescriptor property, object target) : base(property.Name, null) { this.property = property; this.target = target; } public override AttributeCollection Attributes { get { return property.Attributes; } } public override Type ComponentType { get { return property.ComponentType; } } public override bool IsReadOnly { get { return property.IsReadOnly; } } public override Type PropertyType { get { return property.PropertyType; } } public override bool CanResetValue(object component) { return property.CanResetValue(target); } public override object GetValue(object component) { return property.GetValue(target); } public override void ResetValue(object component) { property.ResetValue(target); } public override void SetValue(object component, object value) { property.SetValue(target, value); } public override bool ShouldSerializeValue(object component) { return property.ShouldSerializeValue(target); } } } } // File provided for Reference Use Only by Microsoft Corporation (c) 2007. // Copyright (c) Microsoft Corporation. All rights reserved.
Link Menu

This book is available now!
Buy at Amazon US or
Buy at Amazon UK
- MaskedTextBox.cs
- StringFunctions.cs
- FontResourceCache.cs
- SqlTrackingQuery.cs
- ProtocolViolationException.cs
- SystemShuttingDownException.cs
- MemberHolder.cs
- SynchronousChannel.cs
- WorkflowInvoker.cs
- EventMappingSettings.cs
- BitmapFrame.cs
- AdPostCacheSubstitution.cs
- DecimalFormatter.cs
- XPathBinder.cs
- XmlILConstructAnalyzer.cs
- LinqTreeNodeEvaluator.cs
- UpdateRecord.cs
- MenuItem.cs
- LabelEditEvent.cs
- DESCryptoServiceProvider.cs
- CredentialCache.cs
- ExtensibleClassFactory.cs
- SessionEndingEventArgs.cs
- SatelliteContractVersionAttribute.cs
- InstanceDataCollection.cs
- EqualityComparer.cs
- DateTimeConverter2.cs
- HttpProfileGroupBase.cs
- PersistenceContext.cs
- SerializationException.cs
- FilterQuery.cs
- XhtmlBasicSelectionListAdapter.cs
- TypeCodeDomSerializer.cs
- BooleanStorage.cs
- AtomServiceDocumentSerializer.cs
- FieldNameLookup.cs
- KeyGestureValueSerializer.cs
- WindowsStartMenu.cs
- BitmapImage.cs
- Drawing.cs
- LinqDataSourceUpdateEventArgs.cs
- securitymgrsite.cs
- DPCustomTypeDescriptor.cs
- Resources.Designer.cs
- securitycriticaldataformultiplegetandset.cs
- FreezableOperations.cs
- XPathNavigatorKeyComparer.cs
- WindowsStatic.cs
- StrokeNodeData.cs
- NativeMethods.cs
- SelectionListDesigner.cs
- ChangesetResponse.cs
- SelectionRange.cs
- WindowsAuthenticationEventArgs.cs
- MissingFieldException.cs
- HtmlButton.cs
- WindowVisualStateTracker.cs
- PointCollection.cs
- InternalControlCollection.cs
- Win32Interop.cs
- PathSegment.cs
- RuleSettingsCollection.cs
- SecondaryViewProvider.cs
- StateWorkerRequest.cs
- BooleanProjectedSlot.cs
- LinkClickEvent.cs
- SqlDataReader.cs
- _SslSessionsCache.cs
- KeyManager.cs
- StorageScalarPropertyMapping.cs
- IProvider.cs
- NodeLabelEditEvent.cs
- XmlDocument.cs
- DES.cs
- SQLRoleProvider.cs
- DataColumnChangeEvent.cs
- DataGridPageChangedEventArgs.cs
- MetadataCache.cs
- BinaryUtilClasses.cs
- UnconditionalPolicy.cs
- SchemaNamespaceManager.cs
- UnsafeNativeMethods.cs
- AtomMaterializer.cs
- OrderByQueryOptionExpression.cs
- ChangeProcessor.cs
- EntityCollection.cs
- ContextMenu.cs
- CodeGenerator.cs
- QualifiedId.cs
- TreeBuilderBamlTranslator.cs
- PiiTraceSource.cs
- CommandTreeTypeHelper.cs
- PowerStatus.cs
- XsdDateTime.cs
- SendMailErrorEventArgs.cs
- SimpleType.cs
- EmptyEnumerator.cs
- ProtocolsConfiguration.cs
- SqlProviderManifest.cs
- ScrollBar.cs