コード例 #1
0
ファイル: LemurOscService.cs プロジェクト: zoombapup/ATF
        /// <summary>
        /// Adds OSC addresses (one for the x-coordinate and one for the y-coordinate) for a list
        /// of DOM children that have attributes that are arrays of floats. Each array of floats
        /// represents a 2D point where the first float is the x coordinate and the second float
        /// is the y coordinate.</summary>
        /// <param name="childInfo">The child info which defines the list of children of a selected DomNode</param>
        /// <param name="childAttributeDesc">The attribute on each child that defines the array of floats</param>
        /// <param name="oscAddress">The base OSC address to use. "/x" and "/y" will be appended for
        /// the x-coordinate array and the y-coordinate array, which is how Lemur sends and receives
        /// 2-D point arrays.</param>
        /// <returns>The base OSC address, with possible changes to make it legal.</returns>
        public string Add2DPointProperty(ChildInfo childInfo, AttributePropertyDescriptor childAttributeDesc, string oscAddress)
        {
            oscAddress = OscServices.FixPropertyAddress(oscAddress);

            var xCoordDesc = new ChildListFloatingPointArrayDesc(childInfo, childAttributeDesc, 0);

            AddPropertyAddress(xCoordDesc, oscAddress + "/x");

            var yCoordDesc = new ChildListFloatingPointArrayDesc(childInfo, childAttributeDesc, 1);

            AddPropertyAddress(yCoordDesc, oscAddress + "/y");

            return(oscAddress);
        }
コード例 #2
0
ファイル: LemurOscService.cs プロジェクト: zoombapup/ATF
 public ChildListFloatingPointArrayDesc(ChildInfo childInfo, AttributePropertyDescriptor childAttributeDesc, int coordinateIndex)
     : base(
         childAttributeDesc.Name,
         childAttributeDesc.AttributeInfo,
         childInfo,
         childAttributeDesc.Category,
         childAttributeDesc.Description,
         childAttributeDesc.IsReadOnly,
         null, //editor
         childAttributeDesc.Converter)
 {
     m_childInfo          = childInfo;
     m_childAttributeDesc = childAttributeDesc;
     m_coordinateIndex    = coordinateIndex;
 }
コード例 #3
0
ファイル: SchemaLoader.cs プロジェクト: uhacz/bitBoxTool
        /// <summary>
        /// Method called after the schema set has been loaded and the DomNodeTypes have been created, but
        /// before the DomNodeTypes have been frozen. This means that DomNodeType.SetIdAttribute, for example, has
        /// not been called on the DomNodeTypes. Is called shortly before OnDomNodeTypesFrozen.
        /// Defines DOM adapters on the DOM types.</summary>
        /// <param name="schemaSet">XML schema sets being loaded</param>
        protected override void OnSchemaSetLoaded(XmlSchemaSet schemaSet)
        {
            foreach (XmlSchemaTypeCollection typeCollection in GetTypeCollections())
            {
                m_namespace      = typeCollection.TargetNamespace;
                m_typeCollection = typeCollection;
                bitBoxSchema.Initialize(typeCollection);

                bitBoxSchema.graphType.Type.Define(new ExtensionInfo <SceneEditingContext>());
                bitBoxSchema.graphType.Type.Define(new ExtensionInfo <NodeEditingContext>());
                bitBoxSchema.graphType.Type.Define(new ExtensionInfo <SceneDocument>());
                //bitBoxSchema.graphType.Type.Define(new ExtensionInfo<UniqueIdValidator>());

                // register extensions
                //bitBoxSchema.graphType.Type.Define(new ExtensionInfo<Game>());
                //bitBoxSchema.graphType.Type.Define(new ExtensionInfo<ReferenceValidator>());
                //bitBoxSchema.graphType.Type.Define(new ExtensionInfo<UniqueIdValidator>());
                //
                //bitBoxSchema.nodeType.Type.Define(new ExtensionInfo<GameObject>());
                //bitBoxSchema.MeshNode.Type.Define(new ExtensionInfo<Dwarf>());

                //bitBoxSchema.MeshNode.Type.Define(new ExtensionInfo<MeshNode>());


                var creator = new AdapterCreator <CustomTypeDescriptorNodeAdapter>();

                foreach (DomNodeType type in GetNodeTypes(bitBoxSchema.nodeType.Type))
                {
                    type.AddAdapterCreator(creator);

                    string defaultNodeName = type.Name.Split(':').Last().Replace("Node", "");
                    type.SetTag(new NodeTypePaletteItem(type, defaultNodeName, defaultNodeName.Localize(), null));

                    PropertyDescriptorCollection propDescs = new PropertyDescriptorCollection(null);
                    foreach (AttributeInfo attr in type.Attributes)
                    {
                        IPropertyEditor             editor            = PropertyEditorFactory.createEditorForAttribute(attr);
                        AttributePropertyDescriptor attributePropDesc = new AttributePropertyDescriptor(attr.Name.Localize(), attr, "Attributes".Localize(), null, false, editor);

                        propDescs.Add(attributePropDesc);
                    }

                    type.SetTag(propDescs);
                }
                break;
            }
        }
コード例 #4
0
        /// <summary>
        /// Does the command</summary>
        /// <param name="commandTag">Command to be done</param>
        public virtual void DoCommand(object commandTag)
        {
            ITransactionContext transactionContext = m_editingContext.As <ITransactionContext>();

            switch ((Command)commandTag)
            {
            case Command.CopyProperty:
            {
                if (!(m_descriptor is ChildPropertyDescriptor))
                {
                    var lastObject = m_editingContext.Items.LastOrDefault();
                    m_copyDescriptor = m_descriptor;
                    m_copyValue      = m_descriptor.GetValue(lastObject);
                }
            }
            break;

            case Command.PasteProperty:
            {
                transactionContext.DoTransaction(delegate
                    {
                        foreach (object item in m_editingContext.Items)
                        {
                            PropertyUtils.SetProperty(item, m_descriptor, m_copyValue);
                        }
                    },
                                                 string.Format("Paste: {0}".Localize("'Paste' is a verb and this is the name of a command"),
                                                               m_descriptor.DisplayName));
            }
            break;

            case Command.ResetProperty:
                transactionContext.DoTransaction(delegate
                {
                    PropertyUtils.ResetProperty(m_editingContext.Items, m_descriptor);
                },
                                                 string.Format("Reset: {0}".Localize("'Reset' is a verb and this is the name of a command"),
                                                               m_descriptor.DisplayName));
                break;

            case Command.CopyAll:
            {
                m_descriptorToValue.Clear();
                var lastObject = m_editingContext.Items.LastOrDefault();
                foreach (var descriptor in m_editingContext.PropertyDescriptors)
                {
                    if ((descriptor is ChildPropertyDescriptor))
                    {
                        continue;
                    }

                    AttributePropertyDescriptor attr = descriptor as AttributePropertyDescriptor;
                    if (attr != null && attr.AttributeInfo.IsIdAttribute)
                    {
                        continue;
                    }

                    m_descriptorToValue.Add(descriptor.GetPropertyDescriptorKey(),
                                            descriptor.GetValue(lastObject));
                }
            }
            break;

            case Command.PasteAll:
            {
                transactionContext.DoTransaction(delegate
                    {
                        foreach (var descriptor in m_editingContext.PropertyDescriptors)
                        {
                            if (descriptor.IsReadOnly)
                            {
                                continue;
                            }
                            ;
                            object value;
                            if (m_descriptorToValue.TryGetValue(descriptor.GetPropertyDescriptorKey(), out value))
                            {
                                foreach (object item in m_editingContext.Items)
                                {
                                    PropertyUtils.SetProperty(item,
                                                              descriptor,
                                                              value);
                                }
                            }
                        }
                    }, "Paste All".Localize("'Paste' is a verb and this is the name of a command"));
            }
            break;

            case Command.ResetAll:
                transactionContext.DoTransaction(delegate
                {
                    foreach (PropertyDescriptor descriptor in m_editingContext.PropertyDescriptors)
                    {
                        foreach (object item in m_editingContext.Items)
                        {
                            if (descriptor.CanResetValue(item))
                            {
                                descriptor.ResetValue(item);
                            }
                        }
                    }
                },
                                                 "Reset All Properties".Localize("'Reset' is a verb and this is the name of a command"));
                break;

            case Command.ViewInTextEditor:
            {
                var fileUriEditor = m_descriptor.GetEditor(typeof(UITypeEditor)) as FileUriEditor;
                var fileUri       = m_descriptor.GetValue(m_editingContext.Items.LastOrDefault()) as Uri;
                if (fileUri != null && File.Exists(fileUri.LocalPath))
                {
                    Process.Start(fileUriEditor.AssociatedTextEditor, fileUri.LocalPath);
                }
            }
            break;
            }
        }
コード例 #5
0
        /// <summary>
        /// Checks whether the client can do the command if it handles it</summary>
        /// <param name="commandTag">Command to be done</param>
        /// <returns>True if client can do the command</returns>
        public virtual bool CanDoCommand(object commandTag)
        {
            if (commandTag is Command && m_editingContext != null)
            {
                switch ((Command)commandTag)
                {
                case Command.CopyProperty:
                    return(m_descriptor != null &&
                           !(m_descriptor is ChildPropertyDescriptor) &&
                           !(m_descriptor is ChildAttributeCollectionPropertyDescriptor));

                case Command.PasteProperty:
                {
                    var lastObject = m_editingContext.Items.LastOrDefault();

                    return(m_descriptor != null && CanPaste(m_copyValue, m_copyDescriptor, m_descriptor,
                                                            m_descriptor.GetValue(lastObject)));
                }

                case Command.ResetProperty:
                    return(CanResetValue(m_editingContext.Items, m_descriptor));

                case Command.CopyAll:
                {
                    foreach (var descriptor in m_editingContext.PropertyDescriptors)
                    {
                        if ((descriptor is ChildPropertyDescriptor) ||
                            (descriptor is ChildAttributeCollectionPropertyDescriptor))
                        {
                            continue;
                        }
                        AttributePropertyDescriptor attr = descriptor as AttributePropertyDescriptor;
                        if (attr != null && attr.AttributeInfo.IsIdAttribute)
                        {
                            continue;
                        }
                        return(true);
                    }
                    break;
                }

                case Command.PasteAll:
                    return(m_descriptorToValue.Count > 0);

                case Command.ResetAll:
                    foreach (PropertyDescriptor descriptor in m_editingContext.PropertyDescriptors)
                    {
                        if (CanResetValue(m_editingContext.Items, descriptor))
                        {
                            return(true);
                        }
                    }
                    break;


                case Command.ViewInTextEditor:
                    if (m_descriptor != null && m_descriptor.GetEditor(typeof(UITypeEditor)) is FileUriEditor)
                    {
                        return(true);
                    }
                    break;
                }
            }

            return(false);
        }
コード例 #6
0
        void AddProperty(DomNodeType domNodeType, SF.Tong.Schema.Property prop, PropertyDescriptorCollection newDescs)
        {
            if (prop.Type == SF.Tong.Schema.PropertyType.Enum)
            {
                SF.Tong.Schema.EnumTypeInfo enumInfo;
                if (!m_EnumDefines.TryGetValue(prop.TypeName, out enumInfo))
                {
                    Outputs.WriteLine(OutputMessageType.Error, "Invalid enum type {1} for property {0}", prop.Name, prop.TypeName);
                    return;
                }

                AttributeInfo newAttr = null;
                if (prop.IsArray)
                {
                    newAttr = new AttributeInfo(prop.Name, enumInfo.ArrayValueType);
                }
                else
                {
                    newAttr = new AttributeInfo(prop.Name, enumInfo.SingleValueType);
                }

                if (prop.Default == null)
                {
                    newAttr.DefaultValue = enumInfo.Value[0];
                }
                else
                {
                    newAttr.DefaultValue = prop.Default;
                }
                newAttr.AddRule(enumInfo.EnumRule);
                var newDesc = new AttributePropertyDescriptor(newAttr.Name, newAttr, "Node", newAttr.Name, false, new EnumUITypeEditor(enumInfo.Value), new EnumTypeConverter(enumInfo.Value));
                newDescs.Add(newDesc);
                domNodeType.Define(newAttr);
                return;
            }

            var propTypeInfo = m_PropertyInfos[(int)prop.Type];

            if (propTypeInfo.AttributeInfo != null)
            {
                AttributeInfo newAttr = null;
                if (prop.IsArray)
                {
                    newAttr = propTypeInfo.ListAttributeInfo.Clone(prop.Name);
                }
                else
                {
                    newAttr = propTypeInfo.AttributeInfo.Clone(prop.Name);
                }

                if (!string.IsNullOrEmpty(prop.Default))
                {
                    newAttr.DefaultValue = newAttr.Type.Convert(prop.Default);
                }

                newAttr.AddRule(new GameDataAttributeRule(prop));

                var newDesc = new AttributePropertyDescriptor(newAttr.Name, newAttr, "Node", newAttr.Name, false, propTypeInfo.Editor, propTypeInfo.Converter);
                newDescs.Add(newDesc);
                domNodeType.Define(newAttr);
            }
            else if (propTypeInfo.ChildInfo != null)
            {
                var newChild = propTypeInfo.ChildInfo.Clone(prop.Name, prop.IsArray);

                newChild.AddRule(new GameDataChildRule(prop));

                object editor  = m_ChildCollectionEditor;
                var    newDesc = new ChildPropertyDescriptor(newChild.Name, newChild, "Node", newChild.Name, false, editor, propTypeInfo.Converter);
                newDescs.Add(newDesc);
                domNodeType.Define(newChild);
            }
        }
コード例 #7
0
        DomNodeType CreateDOMType(Type clrType)
        {
            var nodeType = new DomNodeType(clrType.Name);

            var propertyDescs = new PropertyDescriptorCollection(null);
            var properties    = clrType.GetProperties();

            foreach (var prop in properties)
            {
                var                propType = prop.PropertyType;
                AttributeInfo      newAttr  = null;
                PropertyDescriptor propDesc = null;

                if (propType.IsClass && propType != typeof(string))
                {
                    ChildInfo newChild = null;
                    object    editor   = null;

                    var childCLRType = propType.IsArray ? propType.GetElementType() : propType;
                    newChild = new ChildInfo(prop.Name, CreateDOMType(childCLRType), propType.IsArray);
                    nodeType.Define(newChild);
                    if (propType.IsArray && clrType != typeof(SF.Tong.Schema.EditorSocket))
                    {
                        editor = m_ChildCollectionEditor;
                    }

                    propDesc = new ChildPropertyDescriptor(prop.Name, newChild, "Node", prop.Name, false, editor);
                }
                else if (propType.IsEnum)
                {
                    if (propType.IsArray)
                    {
                        newAttr = new AttributeInfo(prop.Name, AttributeType.StringArrayType);
                        newAttr.AddRule(new StringEnumRule(Enum.GetNames(propType)));
                    }
                    else
                    {
                        newAttr = new AttributeInfo(prop.Name, AttributeType.StringType);
                        newAttr.AddRule(new StringEnumRule(Enum.GetNames(propType)));
                    }
                }
                else
                {
                    if (propType.IsArray)
                    {
                        switch (propType.Name)
                        {
                        case "String":
                            // Consider them as string crc always?
                            newAttr = new AttributeInfo(prop.Name, new AttributeType(AttributeTypes.SingleArray.ToString(), typeof(string[])));
                            newAttr.AddRule(new StringHashRule());
                            break;

                        case "int":
                            newAttr = new AttributeInfo(prop.Name, new AttributeType(AttributeTypes.Int32Array.ToString(), typeof(int[])));
                            break;

                        case "boolean":
                            newAttr = new AttributeInfo(prop.Name, new AttributeType(AttributeTypes.BooleanArray.ToString(), typeof(bool[])));
                            break;

                        case "Single":
                            newAttr = new AttributeInfo(prop.Name, new AttributeType(AttributeTypes.SingleArray.ToString(), typeof(float[])));
                            break;

                        default:
                            throw new NotSupportedException("Not supported data type for DOM type gen:" + prop.PropertyType.Name);
                        }
                    }
                    else
                    {
                        switch (propType.Name)
                        {
                        case "String":
                            // Consider them as string crc always?
                            newAttr = new AttributeInfo(prop.Name, AttributeType.StringType);
                            newAttr.AddRule(new StringHashRule());
                            break;

                        case "int":
                            newAttr = new AttributeInfo(prop.Name, AttributeType.IntType);
                            break;

                        case "boolean":
                            newAttr = new AttributeInfo(prop.Name, AttributeType.BooleanType);
                            break;

                        case "Single":
                            newAttr = new AttributeInfo(prop.Name, AttributeType.FloatType);
                            break;

                        default:
                            throw new NotSupportedException("Not supported data type for DOM type gen:" + prop.PropertyType.Name);
                        }
                    }
                }

                if (newAttr != null)
                {
                    propDesc = new AttributePropertyDescriptor(prop.Name, newAttr, "Node", prop.Name, false);
                    nodeType.Define(newAttr);
                }

                if (propDesc != null)
                {
                    propertyDescs.Add(propDesc);
                }
            }

            nodeType.SetTag(propertyDescs);

            return(nodeType);
        }
コード例 #8
0
 // 'byteIndex' is 0 for the lowest byte (green), 1 for next lowest byte (blue),
 //  and 2 for the third byte (red).
 public ByteAttributePropertyDescriptor(AttributePropertyDescriptor original, byte byteIndex)
     : base(original.Name, original.AttributeInfo, original.Category, original.Description, original.IsReadOnly)
 {
     m_bitShift = byteIndex * 8;
 }
コード例 #9
0
        public void TestEquality()
        {
            var attrType1 = new AttributeType("xkcd", typeof(string));
            var attrInfo1 = new AttributeInfo("xkcd", attrType1);

            attrInfo1.DefaultValue = "Firefly";
            var desc1 = new AttributePropertyDescriptor(
                "xkcd", attrInfo1, "Category 1", "A commonly used word or phrase in the xkcd comic", true);
            int originalHashCode = desc1.GetHashCode();

            // test if two identically created property descriptors compare as being equal
            var desc2 = new AttributePropertyDescriptor(
                "xkcd", attrInfo1, "Category 1", "A commonly used word or phrase in the xkcd comic", true);

            Assert.AreEqual(desc1, desc2);
            Assert.AreEqual(desc1.GetHashCode(), desc2.GetHashCode());

            // test category being different; oddly, although I think they should not be considered equal,
            //  the .Net PropertyDescriptor ignores the difference in category name. So, I'm guessing that
            //  the AttributePropertyDescriptor should behave the same as PropertyDescriptor.
            var desc3 = new AttributePropertyDescriptor(
                "xkcd", attrInfo1, "Category 2", "A commonly used word or phrase in the xkcd comic", true);

            Assert.AreEqual(desc1, desc3);
            Assert.AreEqual(desc1.GetHashCode(), desc3.GetHashCode());

            // test description being different; similarly here, the .Net PropertyDescriptor doesn't care.
            var desc4 = new AttributePropertyDescriptor(
                "xkcd", attrInfo1, "Category 1", "slightly different description", true);

            Assert.AreEqual(desc1, desc4);
            Assert.AreEqual(desc1.GetHashCode(), desc4.GetHashCode());

            // test readOnly being different; ditto for read-only flag!
            var desc5 = new AttributePropertyDescriptor(
                "xkcd", attrInfo1, "Category 1", "A commonly used word or phrase in the xkcd comic", false);

            Assert.AreEqual(desc1, desc5);
            Assert.AreEqual(desc1.GetHashCode(), desc5.GetHashCode());

            // test that the hash code hasn't changed after using the AttributeInfo
            var domNodeType = new DomNodeType("WebComic", DomNodeType.BaseOfAllTypes);
            var attrInfo2   = new AttributeInfo("xkcd", attrType1);

            domNodeType.Define(attrInfo2);
            Assert.AreEqual(desc1.GetHashCode(), originalHashCode);

            // test that the hash code hasn't changed after creating a derived DomNodeType
            var derivedDomNodeType = new DomNodeType("ScientificWebComic", domNodeType);
            var derivedAttrInfo    = new AttributeInfo("xkcd", attrType1);

            derivedDomNodeType.Define(derivedAttrInfo);
            Assert.AreEqual(desc1.GetHashCode(), originalHashCode);

            // test that an AttributeInfo used in a derived DomNodeType doesn't change equality or hash code
            var desc6 = new AttributePropertyDescriptor(
                "xkcd", derivedAttrInfo, "Category 1", "A commonly used word or phrase in the xkcd comic", true);

            Assert.AreEqual(desc1, desc6);
            Assert.AreEqual(desc1.GetHashCode(), desc6.GetHashCode());
        }
コード例 #10
0
            private void RefreshValue()
            {
                try
                {
                    m_refreshing = true;

                    object value = m_context.GetValue();
                    if (value == null)
                    {
                        this.Enabled = false;
                    }
                    else
                    {
                        this.Enabled = true;
                        bool textEditable =
                            m_context.Descriptor.Converter == null &&
                            m_context.Descriptor.Converter.CanConvertFrom((value.GetType()));

                        bool valueMatched = false;
                        if (ConvertIdToDisplayCallback != null)
                        {
                            this.Text = ConvertIdToDisplayCallback((string)value, ref valueMatched);
                        }

                        if (valueMatched)
                        {
                            bool defaultValue = false;
                            AttributePropertyDescriptor attribute = m_context.Descriptor as AttributePropertyDescriptor;
                            if (attribute != null)
                            {
                                if (value.Equals(attribute.AttributeInfo.DefaultValue))
                                {
                                    defaultValue = true;
                                }
                            }

                            if (defaultValue)
                            {
                                Font = m_defaultFont;
                                //  this.ForeColor = m_defaultColor;
                            }
                            else
                            {
                                if (textEditable)
                                {
                                    Font = m_boldFont;
                                    // this.ForeColor = System.Drawing.Color.CadetBlue;
                                }
                                else
                                {
                                    Font = m_boldFont;
                                    // this.ForeColor = m_defaultColor;
                                }
                            }
                        }
                        else
                        {
                            Font = m_boldFont;
                            //  this.ForeColor = m_defaultColor;
                        }
                    }
                }
                finally
                {
                    m_refreshing = false;
                }
            }
コード例 #11
0
ファイル: TestPropertyUtils.cs プロジェクト: zparr/ATF
        public void TestGetPropertyDescriptorKey()
        {
            // First use AttributePropertyDescriptor and MultiPropertyDescriptor
            {
                // Make sure that different property descriptor objects with the same Name, Category and Type
                //  have the same hash code, using PropertyUtils.GetPropertyDescriptorHash().
                var attrPropertyDescriptor = new AttributePropertyDescriptor(
                    "TestName", new AttributeInfo("TestAttrName", new AttributeType("TestAttrName", typeof(string))),
                    "TestCategory", "Test description", false);
                var multiPropertyDescriptor = new MultiPropertyDescriptor(attrPropertyDescriptor);
                Assert.IsTrue(IsSameHashKey(attrPropertyDescriptor, multiPropertyDescriptor));

                // Make sure that null Category names work, too.
                attrPropertyDescriptor = new AttributePropertyDescriptor(
                    "TestName", new AttributeInfo("TestAttrName", new AttributeType("TestAttrName", typeof(string))),
                    null, "Test description", false);
                multiPropertyDescriptor = new MultiPropertyDescriptor(attrPropertyDescriptor);
                Assert.IsTrue(IsSameHashKey(attrPropertyDescriptor, multiPropertyDescriptor));

                // Make sure that if the Name and Category and identical, that it works with other property
                //  descriptors who also have identical Name and Category strings. This makes sure that we
                //  are not using 'xor' between the Name and Category.
                attrPropertyDescriptor = new AttributePropertyDescriptor(
                    "SameName", new AttributeInfo("TestAttrName", new AttributeType("TestAttrName", typeof(string))),
                    "SameName", "Name and Category are the same!", false);
                multiPropertyDescriptor = new MultiPropertyDescriptor(attrPropertyDescriptor);
                Assert.IsTrue(IsSameHashKey(attrPropertyDescriptor, multiPropertyDescriptor));

                var d2 = new AttributePropertyDescriptor(
                    "AnotherSameName", new AttributeInfo("TestAttrName", new AttributeType("TestAttrName", typeof(string))),
                    "AnotherSameName", "Name and Category are the same!", false);
                var m2 = new MultiPropertyDescriptor(d2);
                Assert.IsTrue(IsSameHashKey(d2, m2));

                Assert.IsTrue(!IsSameHashKey(attrPropertyDescriptor, d2));

                // Make sure that if the Name and Category are swapped, that they yield different codes.
                attrPropertyDescriptor = new AttributePropertyDescriptor(
                    "Name1", new AttributeInfo("TestAttrName", new AttributeType("TestAttrName", typeof(string))),
                    "Name2", "Test description", false);
                d2 = new AttributePropertyDescriptor(
                    "Name2", new AttributeInfo("TestAttrName", new AttributeType("TestAttrName", typeof(string))),
                    "Name1", "Test description", false);
                Assert.IsTrue(!IsSameHashKey(attrPropertyDescriptor, d2));
            }

            // Now use a stub property descriptor and MultiPropertyDescriptor
            {
                // Make sure that different property descriptor objects with the same Name, Category and Type
                //  have the same hash code, using PropertyUtils.GetPropertyDescriptorHash().
                var stubPropertyDescriptor  = new MyPropertyDescriptor("TestName", "TestCategory", typeof(string));
                var multiPropertyDescriptor = new MultiPropertyDescriptor(stubPropertyDescriptor);
                Assert.IsTrue(IsSameHashKey(stubPropertyDescriptor, multiPropertyDescriptor));

                // Make sure that null Category names work, too.
                stubPropertyDescriptor  = new MyPropertyDescriptor("TestName", null, typeof(string));
                multiPropertyDescriptor = new MultiPropertyDescriptor(stubPropertyDescriptor);
                Assert.IsTrue(IsSameHashKey(stubPropertyDescriptor, multiPropertyDescriptor));

                // Make sure that if the Name and Category and identical, that it works with other property
                //  descriptors who also have identical Name and Category strings. This makes sure that we
                //  are not using 'xor' between the Name and Category.
                stubPropertyDescriptor  = new MyPropertyDescriptor("SameName", "SameName", typeof(string));
                multiPropertyDescriptor = new MultiPropertyDescriptor(stubPropertyDescriptor);
                Assert.IsTrue(IsSameHashKey(stubPropertyDescriptor, multiPropertyDescriptor));

                var d2 = new MyPropertyDescriptor("AnotherSameName", "AnotherSameName", typeof(string));
                var m2 = new MultiPropertyDescriptor(d2);
                Assert.IsTrue(IsSameHashKey(d2, m2));

                Assert.IsTrue(!IsSameHashKey(stubPropertyDescriptor, d2));

                // Make sure that if the Name and Category are swapped, that they yield different codes.
                stubPropertyDescriptor = new MyPropertyDescriptor("Name1", "Name2", typeof(string));
                d2 = new MyPropertyDescriptor("Name2", "Name1", typeof(string));
                Assert.IsTrue(!IsSameHashKey(stubPropertyDescriptor, d2));
            }
        }