Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Passing a context containing properties to a TypeConverter

I'm looking for a way of passing additional information to a TypeConverter in order to provide some context for conversions without creating a custom constructor.

That extra information passed would be original object (known at compile time as an interface) that contains the property that I am converting. It contains properties of its own like Id that are useful for lookups to convert related information.

I've had a look at the documentation for ITypeDescriptorContext but I haven't found a clear-cut example of how to implement that interface. I'm also not convinced it's the tool I need.

At the moment, in my code I'm calling:

// For each writeable property in my output class.

// If property has TypeConverterAttribute
var converted = converter.ConvertFrom(propertyFromOriginalObject)

propertyInfo.SetValue(output, converted, null);

What I'd like to do is something like.

// Original object is an interface at compile time.
var mayNewValue = converter.ConvertFrom(originalObject, propertyFromOriginalObject)

I'd like to be able to use one of the overloads to do what I need so that any custom converters can inherit from TypeConverter rather than a base class with a custom constructor as that would make life easier with dependency injection and use DependencyResolver.Current.GetService(type) from MVC to initialise my converter.

Any ideas?

like image 919
James South Avatar asked Feb 27 '15 13:02

James South


1 Answers

The method you want to use is clearly this overload: TypeConverter.ConvertFrom Method (ITypeDescriptorContext, CultureInfo, Object)

It will allow you to pass a pretty generic context. The Instance property represents the object instance you're working on, and the PropertyDescriptor property represents the property definition of the property value being converted.

For example, the Winforms property grid does exactly that.

So, you'll have to provide your own context. Here is a sample one:

public class MyContext : ITypeDescriptorContext
{
    public MyContext(object instance, string propertyName)
    {
        Instance = instance;
        PropertyDescriptor = TypeDescriptor.GetProperties(instance)[propertyName];
    }

    public object Instance { get; private set; }
    public PropertyDescriptor PropertyDescriptor { get; private set; }
    public IContainer Container { get; private set; }

    public void OnComponentChanged()
    {
    }

    public bool OnComponentChanging()
    {
        return true;
    }

    public object GetService(Type serviceType)
    {
        return null;
    }
}

So, let's consider a custom converter, as you see it can grab the existing object's property value using one line of code (note this code is compatible with standard existing ITypeDescriptorContext like the property grid one although in real life scenarios, you must check the context for nullity):

public class MyTypeConverter : TypeConverter
{
    public override object ConvertFrom(ITypeDescriptorContext context, CultureInfo culture, object value)
    {
        // get existing value
        object existingPropertyValue = context.PropertyDescriptor.GetValue(context.Instance);

        // do something useful here
        ...
    }
}

Now, if you have this custom object being modified:

public class MySampleObject
{
    public MySampleObject()
    {
        MySampleProp = "hello world";
    }

    public string MySampleProp { get; set; }
}

You can call the converter like this:

MyTypeConverter tc = new MyTypeConverter();
object newValue = tc.ConvertFrom(new MyContext(new MySampleObject(), "MySampleProp"), null, "whatever");
like image 80
Simon Mourier Avatar answered Nov 11 '22 14:11

Simon Mourier