Index: Core/Common/src/Core.Common.Gui/PropertyBag/DynamicPropertyBag.cs
===================================================================
diff -u -r7de564e0db6835c6821f0ce2303a983a2758e7d0 -rd91a531792e48f042fa6c28ef8c0e16b8fa06fba
--- Core/Common/src/Core.Common.Gui/PropertyBag/DynamicPropertyBag.cs (.../DynamicPropertyBag.cs) (revision 7de564e0db6835c6821f0ce2303a983a2758e7d0)
+++ Core/Common/src/Core.Common.Gui/PropertyBag/DynamicPropertyBag.cs (.../DynamicPropertyBag.cs) (revision d91a531792e48f042fa6c28ef8c0e16b8fa06fba)
@@ -42,52 +42,6 @@
return WrappedObject.ToString();
}
- ///
- /// Raises the GetValue event.
- ///
- /// A PropertySpecEventArgs that contains the event data.
- ///
- internal void OnGetValue(PropertySpecEventArgs e, PropertySpec propertySpec)
- {
- var attributeList = new List();
- attributeList.AddRange(propertySpec.Attributes.ToList());
-
- //check all of the attributes: if we find a dynamic one, evaluate it and possibly add/overwrite a static attribute
- foreach (Attribute customAttribute in propertySpec.Attributes)
- {
- if (customAttribute is DynamicReadOnlyAttribute)
- {
- attributeList.RemoveAll(x => x is ReadOnlyAttribute);
-
- if (DynamicReadOnlyAttribute.IsReadOnly(WrappedObject, propertySpec.Name))
- {
- //condition is true: the dynamic attribute should be applied (as static attribute)
- attributeList.Add(new ReadOnlyAttribute(true)); //add static read only attribute
- }
- }
-
- if (customAttribute is DynamicVisibleAttribute)
- {
- attributeList.RemoveAll(x => x is BrowsableAttribute);
-
- if (!DynamicVisibleAttribute.IsVisible(WrappedObject, propertySpec.Name))
- {
- attributeList.Add(new BrowsableAttribute(false));
- }
- }
- }
-
- propertySpec.Attributes = attributeList.ToArray();
-
- var propertyInfo = WrappedObject.GetType().GetProperty(propertySpec.Name);
- var value = propertyInfo.GetValue(WrappedObject, null);
-
- var isNestedPropertiesObject = IsNestedExpandablePropertiesObject(propertyInfo);
-
- // if nested properties object, wrap in DynamicPropertyBag to provide support for things like DynamicReadOnly
- e.Value = isNestedPropertiesObject ? new DynamicPropertyBag(value) : value;
- }
-
private void Initialize(object propertyObject)
{
WrappedObject = propertyObject;
@@ -98,31 +52,6 @@
}
}
- private bool IsNestedExpandablePropertiesObject(System.Reflection.PropertyInfo propertyInfo)
- {
- try
- {
- var typeConverterAttributes = propertyInfo.GetCustomAttributes(typeof(TypeConverterAttribute), false);
- foreach (TypeConverterAttribute typeConverterAttribute in typeConverterAttributes)
- {
- var typeString = typeConverterAttribute.ConverterTypeName;
- var type = Type.GetType(typeString);
- if (type != null)
- {
- if (typeof(ExpandableObjectConverter) == type)
- {
- return true;
- }
- }
- }
- }
- catch (Exception)
- {
- //gulp
- }
- return false;
- }
-
#region ICustomTypeDescriptor explicit interface definitions
#region Implementations delegated to System.ComponentModel.TypeDescriptor
@@ -142,7 +71,7 @@
return TypeDescriptor.GetComponentName(this, true);
}
- public System.ComponentModel.TypeConverter GetConverter()
+ public TypeConverter GetConverter()
{
return TypeDescriptor.GetConverter(this, true);
}
@@ -176,7 +105,7 @@
public PropertyDescriptor GetDefaultProperty()
{
- return Properties.Count > 0 ? new PropertySpecDescriptor(Properties[0], this, Properties[0].Name, null) : null;
+ return Properties.Count > 0 ? new PropertySpecDescriptor(Properties[0], WrappedObject) : null;
}
public PropertyDescriptorCollection GetProperties(Attribute[] attributes)
@@ -190,21 +119,9 @@
foreach (PropertySpec property in Properties)
{
- var attrs = new ArrayList();
+ // Create a new property descriptor for the property item, and add it to the list.
+ var pd = new PropertySpecDescriptor(property, WrappedObject);
- // Additionally, append the custom attributes associated with the
- // PropertySpec, if any.
- if (property.Attributes != null)
- {
- attrs.AddRange(property.Attributes);
- }
-
- Attribute[] attrArray = (Attribute[])attrs.ToArray(typeof(Attribute));
-
- // Create a new property descriptor for the property item, and add
- // it to the list.
- var pd = new PropertySpecDescriptor(property, this, property.Name, attrArray);
-
var propertyOrderAttribute = property.Attributes != null ? property.Attributes.OfType().FirstOrDefault() : null;
if (propertyOrderAttribute != null)
{
Index: Core/Common/src/Core.Common.Gui/PropertyBag/PropertySpecDescriptor.cs
===================================================================
diff -u -r7de564e0db6835c6821f0ce2303a983a2758e7d0 -rd91a531792e48f042fa6c28ef8c0e16b8fa06fba
--- Core/Common/src/Core.Common.Gui/PropertyBag/PropertySpecDescriptor.cs (.../PropertySpecDescriptor.cs) (revision 7de564e0db6835c6821f0ce2303a983a2758e7d0)
+++ Core/Common/src/Core.Common.Gui/PropertyBag/PropertySpecDescriptor.cs (.../PropertySpecDescriptor.cs) (revision d91a531792e48f042fa6c28ef8c0e16b8fa06fba)
@@ -1,19 +1,22 @@
using System;
+using System.Collections.Generic;
using System.ComponentModel;
+using System.Linq;
+using Core.Common.Gui.Attributes;
+
namespace Core.Common.Gui.PropertyBag
{
public class PropertySpecDescriptor : PropertyDescriptor
{
- private readonly DynamicPropertyBag bag;
private readonly PropertySpec item;
+ private readonly object instance;
- public PropertySpecDescriptor(PropertySpec item, DynamicPropertyBag bag, string name, Attribute[] attrs)
- :
- base(name, attrs)
+ public PropertySpecDescriptor(PropertySpec propertySpec, object instance)
+ : base(propertySpec.Name, propertySpec.Attributes)
{
- this.bag = bag;
- this.item = item;
+ item = propertySpec;
+ this.instance = instance;
}
public override Type ComponentType
@@ -28,7 +31,11 @@
{
get
{
- return (Attributes.Matches(ReadOnlyAttribute.Yes));
+ if (Attributes.Matches(new DynamicReadOnlyAttribute()))
+ {
+ return DynamicReadOnlyAttribute.IsReadOnly(instance, item.Name);
+ }
+ return Attributes.Matches(ReadOnlyAttribute.Yes);
}
}
@@ -76,12 +83,87 @@
private PropertySpecEventArgs ReEvaluateAttributes()
{
- // Have the property bag raise an event to get the current value
- // of the property and evaluate the dynamic attributes
+ UpdateDynamicAttributes();
+
+ // Have the property bag raise an event to get the current value of the property:
var e = new PropertySpecEventArgs(item, null);
- bag.OnGetValue(e, e.Property);
- AttributeArray = e.Property.Attributes;
+ OnGetValue(e, e.Property);
+ AttributeArray = e.Property.Attributes; // TODO: Override AttributeArray to reroute to 'item.Attributes'
return e;
}
+
+ private void UpdateDynamicAttributes()
+ {
+ var attributeList = new List();
+ attributeList.AddRange(item.Attributes.ToList());
+
+ //check all of the attributes: if we find a dynamic one, evaluate it and possibly add/overwrite a static attribute
+ foreach (Attribute customAttribute in item.Attributes)
+ {
+ if (customAttribute is DynamicReadOnlyAttribute)
+ {
+ attributeList.RemoveAll(x => x is ReadOnlyAttribute);
+
+ if (DynamicReadOnlyAttribute.IsReadOnly(instance, item.Name))
+ {
+ //condition is true: the dynamic attribute should be applied (as static attribute)
+ attributeList.Add(new ReadOnlyAttribute(true)); //add static read only attribute
+ }
+ }
+
+ if (customAttribute is DynamicVisibleAttribute)
+ {
+ attributeList.RemoveAll(x => x is BrowsableAttribute);
+
+ if (!DynamicVisibleAttribute.IsVisible(instance, item.Name))
+ {
+ attributeList.Add(new BrowsableAttribute(false));
+ }
+ }
+ }
+
+ item.Attributes = attributeList.ToArray();
+ }
+
+ ///
+ /// Raises the GetValue event.
+ ///
+ /// A PropertySpecEventArgs that contains the event data.
+ ///
+ private void OnGetValue(PropertySpecEventArgs e, PropertySpec propertySpec)
+ {
+ var propertyInfo = instance.GetType().GetProperty(propertySpec.Name);
+ var value = propertyInfo.GetValue(instance, null);
+
+ var isNestedPropertiesObject = IsNestedExpandablePropertiesObject(propertyInfo);
+
+ // if nested properties object, wrap in DynamicPropertyBag to provide support for things like DynamicReadOnly
+ e.Value = isNestedPropertiesObject ? new DynamicPropertyBag(value) : value;
+ }
+
+ private bool IsNestedExpandablePropertiesObject(System.Reflection.PropertyInfo propertyInfo)
+ {
+ try
+ {
+ var typeConverterAttributes = propertyInfo.GetCustomAttributes(typeof(TypeConverterAttribute), false);
+ foreach (TypeConverterAttribute typeConverterAttribute in typeConverterAttributes)
+ {
+ var typeString = typeConverterAttribute.ConverterTypeName;
+ var type = Type.GetType(typeString);
+ if (type != null)
+ {
+ if (typeof(ExpandableObjectConverter) == type)
+ {
+ return true;
+ }
+ }
+ }
+ }
+ catch (Exception)
+ {
+ //gulp
+ }
+ return false;
+ }
}
}
\ No newline at end of file
Index: Core/Common/test/Core.Common.Gui.Test/Core.Common.Gui.Test.csproj
===================================================================
diff -u -rb92517dbc9956b930a6cfc7f96a1f762dfa41cf6 -rd91a531792e48f042fa6c28ef8c0e16b8fa06fba
--- Core/Common/test/Core.Common.Gui.Test/Core.Common.Gui.Test.csproj (.../Core.Common.Gui.Test.csproj) (revision b92517dbc9956b930a6cfc7f96a1f762dfa41cf6)
+++ Core/Common/test/Core.Common.Gui.Test/Core.Common.Gui.Test.csproj (.../Core.Common.Gui.Test.csproj) (revision d91a531792e48f042fa6c28ef8c0e16b8fa06fba)
@@ -63,6 +63,7 @@
+
Index: Core/Common/test/Core.Common.Gui.Test/PropertyBag/DynamicPropertyBagTest.cs
===================================================================
diff -u -r7de564e0db6835c6821f0ce2303a983a2758e7d0 -rd91a531792e48f042fa6c28ef8c0e16b8fa06fba
--- Core/Common/test/Core.Common.Gui.Test/PropertyBag/DynamicPropertyBagTest.cs (.../DynamicPropertyBagTest.cs) (revision 7de564e0db6835c6821f0ce2303a983a2758e7d0)
+++ Core/Common/test/Core.Common.Gui.Test/PropertyBag/DynamicPropertyBagTest.cs (.../DynamicPropertyBagTest.cs) (revision d91a531792e48f042fa6c28ef8c0e16b8fa06fba)
@@ -8,67 +8,83 @@
using NUnit.Framework;
-using CategoryComponentModelAttribute = System.ComponentModel.CategoryAttribute;
-
namespace Core.Common.Gui.Test.PropertyBag
{
[TestFixture]
public class DynamicPropertyBagTest
{
[Test]
- public void DynamicPropertyBagReturnsCorrectProperties()
+ public void ParameteredConstructor_ExpectedValues()
{
- var dynamicPropertyBag = new DynamicPropertyBag(new TestProperties());
+ // Setup
+ var propertyObject = new object();
- Assert.AreEqual(4, dynamicPropertyBag.Properties.Count, "Expected property count wrong");
+ // Call
+ var dynamicPropertyBag = new DynamicPropertyBag(propertyObject);
+
+ // Assert
+ CollectionAssert.IsEmpty(dynamicPropertyBag.Properties,
+ "Object has no properties, therefore bag should have none too.");
+ Assert.AreSame(propertyObject, dynamicPropertyBag.WrappedObject);
}
[Test]
- public void DynamicPropertyBagCopiesStaticAttributes()
+ public void GivenTestProperties_WhenConstructing_ThenCorrectNumberOfPropertiesCreated()
{
- var dynamicPropertyBag = new DynamicPropertyBag(new TestProperties());
+ // Setup
+ var propertyObject = new TestProperties();
- PropertySpec nameProperty = null;
- PropertySpec descriptionProperty = null;
+ // Call
+ var dynamicPropertyBag = new DynamicPropertyBag(propertyObject);
- foreach (PropertySpec spec in dynamicPropertyBag.Properties)
- {
- if (spec.Name.Equals("Description"))
- {
- descriptionProperty = spec;
- }
- else if (spec.Name.Equals("Name"))
- {
- nameProperty = spec;
- }
- }
+ // Assert
+ Assert.AreEqual(4, dynamicPropertyBag.Properties.Count, "Expected property count wrong");
+ }
- // asserts
- Assert.IsTrue(nameProperty.Attributes.Any(x => x.GetType() == typeof(CategoryComponentModelAttribute)), "Static Category attribute not copied!");
+ [Test]
+ public void GivenTestProperties_WhenConstructing_ThenPropertySpecsHaveAttributesSet()
+ {
+ // Setup
+ var propertyObject = new TestProperties();
- CollectionAssert.Contains(descriptionProperty.Attributes, ReadOnlyAttribute.Yes, "Static ReadOnly attribute not copied!");
- }
+ // Call
+ var dynamicPropertyBag = new DynamicPropertyBag(propertyObject);
+ // Assert
+ var namePropertySpec = dynamicPropertyBag.Properties.OfType().First(ps => ps.Name == "Name");
+ Assert.IsTrue(namePropertySpec.Attributes.Any(a => a is System.ComponentModel.CategoryAttribute));
+
+ var descriptionPropertySpec = dynamicPropertyBag.Properties.OfType().First(ps => ps.Name == "Description");
+ CollectionAssert.Contains(descriptionPropertySpec.Attributes, ReadOnlyAttribute.Yes,
+ "Should have initialized Attributes of the property spec with declared ReadOnlyAttribute.");
+ }
+
[Test]
- public void DynamicPropertyBagResolvesDynamicAttributesToNothing()
+ public void GivenClassWithDynamicReadOnlyAttribute_WhenNotReadOnly_ThenTypeDescriptorDoesNotHaveReadOnlyAttribute()
{
+ // Setup
var testProperties = new TestProperties
{
IsNameReadOnly = false
};
+ // Precondition
+ var namePropertyAttributes = testProperties.GetType().GetProperty("Name").GetCustomAttributes(true);
+ Assert.IsFalse(namePropertyAttributes.Any(a => a is ReadOnlyAttribute));
+ CollectionAssert.Contains(namePropertyAttributes, new DynamicReadOnlyAttribute());
+ Assert.IsFalse(testProperties.DynamicReadOnlyValidationMethod("Name"));
+
+ // Call
var dynamicPropertyBag = new DynamicPropertyBag(testProperties);
- var propertyDescriptorCollection = ((ICustomTypeDescriptor) dynamicPropertyBag).GetProperties();
+ // Assert
+ PropertyDescriptorCollection propertyDescriptorCollection = dynamicPropertyBag.GetProperties();
+ PropertyDescriptor namePropertyDescriptor = propertyDescriptorCollection.Find("Name", false);
- var namePropertyDescriptor = propertyDescriptorCollection.Find("Name", false);
-
- namePropertyDescriptor.GetValue(dynamicPropertyBag);
-
- // asserts
- Assert.IsTrue(namePropertyDescriptor.Attributes.Matches(new DynamicReadOnlyAttribute()),"Dynamic ReadOnly attribute was not added");
-
- Assert.IsFalse(namePropertyDescriptor.Attributes.Matches(new ReadOnlyAttribute(true)), "Inactive dynamic ReadOnly attribute was resolved to static attribute: wrong.");
+ CollectionAssert.Contains(namePropertyDescriptor.Attributes, new DynamicReadOnlyAttribute(),
+ "DynamicReadOnlyAttribute declared on Name property should also be present on PropertyDescriptor.");
+ Assert.IsFalse(namePropertyDescriptor.Attributes.OfType().Any(a => a is ReadOnlyAttribute),
+ "As Name property has no ReadOnlyAttribute nor does DyanmicReadOnlyValidationMethod evaluate to true, no ReadOnlyAttribute should be on PropertyDescriptor.");
}
[Test]
@@ -287,7 +303,7 @@
///
[DynamicReadOnly]
[DynamicVisible]
- [CategoryComponentModelAttribute("General")]
+ [System.ComponentModel.Category("General")]
public string Name { get; set; }
public bool IsNameReadOnly { get; set; }
Index: Core/Common/test/Core.Common.Gui.Test/PropertyBag/PropertySpecDescriptorTest.cs
===================================================================
diff -u
--- Core/Common/test/Core.Common.Gui.Test/PropertyBag/PropertySpecDescriptorTest.cs (revision 0)
+++ Core/Common/test/Core.Common.Gui.Test/PropertyBag/PropertySpecDescriptorTest.cs (revision d91a531792e48f042fa6c28ef8c0e16b8fa06fba)
@@ -0,0 +1,48 @@
+using System.ComponentModel;
+
+using Core.Common.Gui.Attributes;
+using Core.Common.Gui.PropertyBag;
+
+using NUnit.Framework;
+
+namespace Core.Common.Gui.Test.PropertyBag
+{
+ [TestFixture]
+ public class PropertySpecDescriptorTest
+ {
+ [Test]
+ [TestCase(false)]
+ [TestCase(true)]
+ public void IsReadOnly_PropertyHasDynamicReadOnlyProperty_ReturnExpectedValue(bool isPropertyReadOnly)
+ {
+ // Setup
+ var instance = new TestClass{ IsPropertyReadOnly = isPropertyReadOnly };
+ var propertySpec = new PropertySpec(instance.GetType().GetProperty("IntegerProperty"));
+ var descriptor = new PropertySpecDescriptor(propertySpec, instance);
+
+ // Call
+ var isReadOnly = descriptor.IsReadOnly;
+
+ // Assert
+ Assert.AreEqual(isPropertyReadOnly, isReadOnly);
+ }
+
+ private class TestClass
+ {
+ public bool IsPropertyReadOnly { get; set; }
+
+ [DynamicReadOnly]
+ public int IntegerProperty { get; set; }
+
+ [DynamicReadOnlyValidationMethod]
+ public bool IsReadOnly(string propertyName)
+ {
+ if (propertyName == "IntegerProperty")
+ {
+ return IsPropertyReadOnly;
+ }
+ return ReadOnlyAttribute.Default.IsReadOnly;
+ }
+ }
+ }
+}
\ No newline at end of file