In the framework there are a couple of different options. In your case you are trying to fit "a square in a round hole". I'd recommend that you use the attribute for primitive types only. For complex types you should instead follow a different approach. There are two common techniques that come to mind: interfaces and custom attributes on the type.
The first technique is to use the custom attribute only as an indicator (if needed) that a ranged value exists. Before using the attribute to determine what the range is look at the actual object and see if it implements a custom interface. If the type implements the custom interface then defer to the custom interface for validation.
The second technique is to apply a special attribute to the type that specifies that it uses more complex range checking. When validating the type's value in the grid look for this attribute. If it exists defer to the class to implement the validation. The special attribute would identify yet another class that actually does the validation. This is similar to how type converters and custom editors work.
[AttributeUsage(AttributeTargets.Class | AttributeTargets.Struct)] public class CustomRangeAttribute : Attribute { public CustomRangeAttribute ( Type rangeValidator ) { }
public Type RangeValidator { get; set; } }
[CustomRange(typeof(MyClassRangeValidator))] public class MyClass { public int Value1 { get; set; } public int Value2 { get; set; } }
public interface ICustomRangeValidator { void Validate ( object data, object value ); }
public class MyClassRangeValidator : ICustomRangeValidator { public void Validate ( object data, object value ) { ... } }
In this case you create a standard interface that all range validators implement. You then expose an attribute to associate an implementation of the interface to a class. The implementation is responsible for validating the data using whatever means it needs. In the property grid whenever you display a property you examine its type for this attribute. If it has one then you use the validator otherwise you check for the custom attribute you already defined. Look in MSDN on how editors and type converters work in .NET for examples of this stuff in action.
Michael Taylor - 11/30/06
|