MergePropertyDescriptor.cs source code in C# .NET

Source code for the .NET framework in C#

                        

Code:

/ FX-1434 / FX-1434 / 1.0 / untmp / whidbey / REDBITS / ndp / fx / src / WinForms / Managed / System / WinForms / PropertyGridInternal / MergePropertyDescriptor.cs / 1 / MergePropertyDescriptor.cs

                            //------------------------------------------------------------------------------ 
// 
//     Copyright (c) Microsoft Corporation.  All rights reserved.
// 
//----------------------------------------------------------------------------- 

/* 
 */ 
namespace System.Windows.Forms.PropertyGridInternal {
    using System.Runtime.Serialization.Formatters; 
    using System.Runtime.Serialization.Formatters.Binary;
    using System.ComponentModel;
    using System.Diagnostics;
    using System; 
    using System.IO;
    using System.Collections; 
    using System.Globalization; 
    using System.Reflection;
    using System.ComponentModel.Design; 
    using System.ComponentModel.Design.Serialization;
    using System.Windows.Forms;
    using System.Drawing;
    using Microsoft.Win32; 

    internal class MergePropertyDescriptor : PropertyDescriptor { 
 
        private PropertyDescriptor[] descriptors;
 
        private enum TriState {
                Unknown,
                Yes,
                No 
        }
 
        private TriState localizable = TriState.Unknown; 
        private TriState readOnly = TriState.Unknown;
        private TriState canReset = TriState.Unknown; 

        private MultiMergeCollection collection;

 
        public MergePropertyDescriptor(PropertyDescriptor[] descriptors) : base(descriptors[0].Name, null)  {
            this.descriptors = descriptors; 
        } 

 
        /// 
        /// 
        ///    
        ///       When overridden in a derived class, gets the type of the 
        ///       component this property
        ///       is bound to. 
        ///     
        /// 
        public override Type ComponentType { 
                get {
                    return descriptors[0].ComponentType;
                }
        } 

        ///  
        ///  
        ///    
        ///       Gets the type converter for this property. 
        ///    
        /// 
        public override TypeConverter Converter {
            get { 
                return descriptors[0].Converter;
            } 
        } 

        public override string DisplayName { 
            get {
                return descriptors[0].DisplayName;
            }
        } 

        ///  
        ///  
        ///    
        ///       Gets a value 
        ///       indicating whether this property should be localized, as
        ///       specified in the .
        ///    
        ///  
        public override bool IsLocalizable {
            get { 
                if (localizable == TriState.Unknown) { 
                    localizable = TriState.Yes;
                    foreach (PropertyDescriptor pd in descriptors) { 
                        if (!pd.IsLocalizable) {
                            localizable = TriState.No;
                            break;
                        } 
                    }
                } 
                return (localizable == TriState.Yes); 
            }
        } 

        /// 
        /// 
        ///     
        ///       When overridden in
        ///       a derived class, gets a value 
        ///       indicating whether this property is read-only. 
        ///    
        ///  
        public override bool IsReadOnly {
            get {
                if (readOnly == TriState.Unknown) {
                    readOnly = TriState.No; 
                    foreach (PropertyDescriptor pd in descriptors) {
                        if (pd.IsReadOnly) { 
                            readOnly = TriState.Yes; 
                            break;
                        } 
                    }
                }
                return (readOnly == TriState.Yes);
            } 
        }
 
 
        /// 
        ///  
        ///    
        ///       When overridden in a derived class,
        ///       gets the type of the property.
        ///     
        /// 
        public override Type PropertyType { 
            get { 
                return descriptors[0].PropertyType;
            } 
        }

        public PropertyDescriptor this[int index] {
            get { 
                return descriptors[index];
            } 
        } 

        ///  
        /// 
        ///    
        ///       When overridden in a derived class, indicates whether
        ///       resetting the will change the value of the 
        ///    .
        ///  
        ///  
        public override bool CanResetValue(object component) {
            Debug.Assert(component is Array, "MergePropertyDescriptor::CanResetValue called with non-array value"); 
            if (canReset == TriState.Unknown) {
                 canReset = TriState.Yes;
                 Array a = (Array)component;
                 for (int i = 0; i < descriptors.Length; i++) { 
                     if (!descriptors[i].CanResetValue(GetPropertyOwnerForComponent(a, i))) {
                         canReset = TriState.No; 
                         break; 
                     }
                 } 

             }
             return (canReset == TriState.Yes);
        } 

        ///  
        ///     This method attempts to copy the given value so unique values are 
        ///     always passed to each object.  If the object cannot be copied it
        ///     will be returned. 
        /// 
        private object CopyValue(object value) {

            // null is always OK 
            if (value == null) {
                return value; 
            } 

            Type type = value.GetType(); 

            // value types are always copies
            if (type.IsValueType) {
                return value; 
            }
 
            object clonedValue = null; 

            // ICloneable is the next easiest thing 
            ICloneable clone = value as ICloneable;
            if (clone != null) {
                clonedValue = clone.Clone();
            } 

            // Next, access the type converter 
            if (clonedValue == null) { 
                TypeConverter converter = TypeDescriptor.GetConverter(value);
                if (converter.CanConvertTo(typeof(InstanceDescriptor))) { 
                    // Instance descriptors provide full fidelity unless
                    // they are marked as incomplete.
                    InstanceDescriptor desc = (InstanceDescriptor)converter.ConvertTo(null, CultureInfo.InvariantCulture, value, typeof(InstanceDescriptor));
                    if (desc != null && desc.IsComplete) { 
                        clonedValue = desc.Invoke();
                    } 
                } 

                // If that didn't work, try conversion to/from string 
                if (clonedValue == null && converter.CanConvertTo(typeof(string)) && converter.CanConvertFrom(typeof(string))) {
                    object stringRep = converter.ConvertToInvariantString(value);
                    clonedValue = converter.ConvertFromInvariantString((string)stringRep);
                } 
            }
 
 

            // How about serialization? 
            if (clonedValue == null && type.IsSerializable) {
                BinaryFormatter f = new BinaryFormatter();
                MemoryStream ms = new MemoryStream();
                f.Serialize(ms, value); 
                ms.Position = 0;
                clonedValue = f.Deserialize(ms); 
            } 

            if (clonedValue != null) { 
                return clonedValue;
            }

            // we failed.  This object's reference will be set on each property. 
            return value;
        } 
 
         /// 
        ///  
        ///    
        ///       Creates a collection of attributes using the
        ///       array of attributes that you passed to the constructor.
        ///     
        /// 
        protected override AttributeCollection CreateAttributeCollection() { 
            return new MergedAttributeCollection(this); 
        }
 

        private object GetPropertyOwnerForComponent(Array a, int i) {
            object propertyOwner = a.GetValue(i);
            if (propertyOwner is ICustomTypeDescriptor) { 
                propertyOwner = ((ICustomTypeDescriptor) propertyOwner).GetPropertyOwner(descriptors[i]);
            } 
            return propertyOwner; 
        }
 
        /// 
        /// 
        ///    
        ///       Gets an editor of the specified type. 
        ///    
        ///  
        public override object GetEditor(Type editorBaseType) { 
            return descriptors[0].GetEditor(editorBaseType);
        } 


        /// 
        ///  
        ///    
        ///       When overridden in a derived class, gets the current 
        ///       value 
        ///       of the
        ///       property on a component. 
        ///    
        /// 
        public override object GetValue(object component) {
            Debug.Assert(component is Array, "MergePropertyDescriptor::GetValue called with non-array value"); 
            bool temp;
            return GetValue((Array)component, out temp); 
        } 

        public object GetValue(Array components, out bool allEqual) { 
            allEqual = true;
            object obj = descriptors[0].GetValue(GetPropertyOwnerForComponent(components, 0));

            if (obj is ICollection) { 
               if (collection == null) {
                   collection = new MultiMergeCollection((ICollection)obj); 
               } 
               else if (collection.Locked) {
                   return collection; 
               }
               else {
                   collection.SetItems((ICollection)obj);
               } 
            }
 
            for (int i = 1; i < descriptors.Length; i++) { 
                object objCur = descriptors[i].GetValue(GetPropertyOwnerForComponent(components, i));
 
                if (collection != null) {
                   if (!collection.MergeCollection((ICollection)objCur)){
                      allEqual = false;
                      return null; 
                   }
                } 
                else if ((obj == null && objCur == null) || 
                         (obj != null && obj.Equals(objCur))) {
 
                   continue;
                }
                else {
                    allEqual = false; 
                    return null;
                } 
            } 

            if (allEqual && collection != null && collection.Count == 0) { 
                return null;
            }

            return (collection != null ? collection : obj); 
        }
 
        internal object[] GetValues(Array components) { 
            object[] values = new object[components.Length];
 
            for (int i = 0; i < components.Length; i++) {
                values[i] = descriptors[i].GetValue(GetPropertyOwnerForComponent(components, i));
            }
            return values; 
        }
 
        ///  
        /// 
        ///     
        ///       When overridden in a derived class, resets the
        ///       value
        ///       for this property
        ///       of the component. 
        ///    
        ///  
        public override void ResetValue(object component) { 

            Debug.Assert(component is Array, "MergePropertyDescriptor::ResetValue called with non-array value"); 
            Array a = (Array)component;
            for (int i = 0; i < descriptors.Length; i++) {
                descriptors[i].ResetValue(GetPropertyOwnerForComponent(a, i));
            } 
        }
 
        private void SetCollectionValues(Array a, IList listValue) { 

            try { 
                if (collection != null) {
                   collection.Locked = true;
                }
 
                // now we have to copy the value into each property.
                object[] values = new object[listValue.Count]; 
 
                listValue.CopyTo(values, 0);
 
                for (int i = 0; i < descriptors.Length; i++) {
                    IList propList = descriptors[i].GetValue(GetPropertyOwnerForComponent(a, i)) as IList;

                    if (propList == null) { 
                       continue;
                    } 
 
                    propList.Clear();
                    foreach (object val in values) { 
                        propList.Add(val);
                    }
                }
            } 
            finally {
               if (collection != null) { 
                  collection.Locked = false; 
               }
            } 

        }

        ///  
        /// 
        ///     
        ///       When overridden in a derived class, sets the value of 
        ///       the component to a different value.
        ///     
        /// 
        public override void SetValue(object component, object value) {
            Debug.Assert(component is Array, "MergePropertyDescriptor::SetValue called with non-array value");
            Array a = (Array)component; 
            if (value is IList && typeof(IList).IsAssignableFrom(PropertyType)) {
                SetCollectionValues(a, (IList)value); 
            } 
            else {
                for (int i = 0; i < descriptors.Length; i++) { 
                    object clonedValue = CopyValue(value);
                    descriptors[i].SetValue(GetPropertyOwnerForComponent(a, i), clonedValue);
                }
            } 
        }
 
        ///  
        /// 
        ///     
        ///       When overridden in a derived class, indicates whether the
        ///       value of
        ///       this property needs to be persisted.
        ///     
        /// 
 
        public override bool ShouldSerializeValue(object component) { 
            Debug.Assert(component is Array, "MergePropertyDescriptor::ShouldSerializeValue called with non-array value");
            Array a = (Array)component; 
            for (int i = 0; i < descriptors.Length; i++) {
                if (!descriptors[i].ShouldSerializeValue(GetPropertyOwnerForComponent(a, i))) {
                    return false;
                } 
            }
            return true; 
        } 

        private class MultiMergeCollection : ICollection { 

            private object[] items;
            private bool     locked;
 
            public MultiMergeCollection(ICollection original) {
               SetItems(original); 
            } 

            ///  
            /// 
            ///     Retrieves the number of items.
            /// 
            public int Count { 
                get {
                    if (items != null) { 
                        return items.Length; 
                    }
                    else { 
                        return 0;
                    }
                }
            } 

 
            ///  
            /// 
            ///     Prevents the contents of the collection from being re-initialized; 
            /// 
            public bool Locked {
               get {
                  return locked; 
               }
               set { 
                  this.locked = value; 
               }
            } 

            object ICollection.SyncRoot {
                get {
                    return this; 
                }
            } 
 
            bool ICollection.IsSynchronized {
                get { 
                    return false;
                }
            }
 
            public void CopyTo(Array array, int index) {
               if (items == null) return; 
 
               Array.Copy(items, 0, array, index, items.Length);
            } 

            public IEnumerator GetEnumerator(){
               if (items != null) {
                  return items.GetEnumerator(); 
               }
               else { 
                  return new object[0].GetEnumerator(); 
               }
            } 

            /// 
            /// 
            /// Ensures that the new collection equals the exisitng one. 
            /// Otherwise, it wipes out the contents of the new collection.
            ///  
            public bool MergeCollection(ICollection newCollection) { 

                if (locked) { 
                   return true;
                }

                if (items.Length != newCollection.Count) { 
                     items = new object[0];
                     return false; 
                } 

                object[] newItems = new object[newCollection.Count]; 
                newCollection.CopyTo(newItems, 0);
                for (int i = 0;i < newItems.Length; i++) {
                     if (((newItems[i] == null) != (items[i] == null)) ||
                         (items[i] != null && !items[i].Equals(newItems[i]))){ 
                           items = new object[0];
                           return false; 
                         } 

                } 
                return true;
            }

            public void SetItems(ICollection collection) { 
                if (locked) {
                  return; 
                } 
                items = new object[collection.Count];
                collection.CopyTo(items, 0); 
            }

        }
 
        private class MergedAttributeCollection : AttributeCollection {
            private MergePropertyDescriptor owner; 
 
            private AttributeCollection[] attributeCollections = null;
            private IDictionary             foundAttributes = null; 

            public MergedAttributeCollection(MergePropertyDescriptor owner) : base((Attribute[])null) {
                this.owner = owner;
            } 

            public override Attribute this[Type attributeType] { 
                get { 
                    return GetCommonAttribute(attributeType);
                } 
            }

            #if false
            private void FullMerge() { 
                Attribute[][] collections = new Attribute[owner.descriptors.Length][];
                for (int i = 0; i < owner.descriptors.Length; i++) { 
                    AttributeCollection attrCollection = owner.descriptors[i].Attributes; 
                    collections[i] = new Attribute[attrCollection.Count];
                    attrCollection.CopyTo(collections[i], 0); 
                    Array.Sort(collections[i], GridEntry.AttributeTypeSorter);
                }

                ArrayList mergedList = new ArrayList(); 

                // merge the sorted lists -- note that lists aren't fully sorted just by 
                // Attribute.TypeId 
                //
                int[] posArray = new int[collections.Length]; 
                for (int i = 0; i < collections[0].Length; i++) {
                    Attribute pivotAttr = collections[0][i];
                    bool match = true;
                    for (int j = 1; j < collections.Length; j++) { 

                        if (posArray[j] >= collections[j].Length) { 
                            match = false; 
                            break;
                        } 

                        // check to see if we're on a match
                        //
                        if (pivotAttr.Equals(collections[j][posArray[j]])) { 
                            posArray[j] += 1;
                            continue; 
                        } 

                        int jPos = posArray[j]; 
                        Attribute jAttr = collections[j][jPos];

                        match = false;
 
                        // if we aren't on a match, check all the items until we're past
                        // where the matching item would be 
                        while (GridEntry.AttributeTypeSorter.Compare(jAttr, pivotAttr) <= 0) { 

                            // got a match! 
                            if (pivotAttr.Equals(jAttr)) {
                                posArray[j] = jPos + 1;
                                match = true;
                                break; 
                            }
 
                            // try again 
                            jPos++;
                            if (jPos < collections[j].Length) { 
                                jAttr = collections[j][jPos];
                            }
                            else {
                                break; 
                            }
                        } 
 
                        // if we got here, there is no match, quit for this guy
                        if (!match) { 
                            posArray[j] = jPos;
                            break;
                        }
                    } 

                    // do we have a match? 
                    if (match) { 
                        mergedList.Add(pivotAttr);
                    } 
                }

                // create our merged array
                Attribute[] mergedAttrs = new Attribute[mergedList.Count]; 
                mergedList.CopyTo(mergedAttrs, 0);
            } 
 
            #endif
 
            private Attribute GetCommonAttribute(Type attributeType) {
                if (attributeCollections == null) {
                    attributeCollections = new AttributeCollection[owner.descriptors.Length];
                    for (int i = 0; i < owner.descriptors.Length; i++) { 
                        attributeCollections[i] = owner.descriptors[i].Attributes;
                    } 
                } 

                if (attributeCollections.Length == 0) { 
                    return GetDefaultAttribute(attributeType);
                }

                Attribute value; 
                if (foundAttributes != null) {
                    value = foundAttributes[attributeType] as Attribute; 
                    if (value != null) { 
                        return value;
                    } 
                }

                value = attributeCollections[0][attributeType];
 
                if (value == null) {
                    return null; 
                } 

                for (int i = 1; i < attributeCollections.Length; i++) { 
                    Attribute newValue = attributeCollections[i][attributeType];
                    if (!value.Equals(newValue)) {
                        value = GetDefaultAttribute(attributeType);
                        break; 
                    }
                } 
 
                if (foundAttributes == null) {
                    foundAttributes = new Hashtable(); 
                }
                foundAttributes[attributeType] = value;
                return value;
            } 
        }
    } 
} 

// File provided for Reference Use Only by Microsoft Corporation (c) 2007.
// Copyright (c) Microsoft Corporation. All rights reserved.


                        

Link Menu

Network programming in C#, Network Programming in VB.NET, Network Programming in .NET
This book is available now!
Buy at Amazon US or
Buy at Amazon UK