views:

207

answers:

3

I am trying to use the LINQtoSQL project in silverlight (its a great project), because its open sourced i figured i could just recompile as a silverlight class library but unfortunately it appears to use a feature not available in silverlight. The TypeDescriptor.GetConverter method.

It uses this to find type converters to properly parse the csv columns to their corresponding CLR types. I have no problem making changes to the linqtocsv sources to make it work in Silverlight, but i just don't know what an equivalent operation would be in silverlight. Various google searches have brought me to this page, but all that says is that the XAML parser has a way of doing this (but it doesn't say how to access this functionality).

In a nutshell, the question is:

how do i replicate the functionality of TypeDescriptor.GetConverter?

I don't necessarily need an exact drop in replacement, i just want to know a good way to do this without hardcoding a bunch of type <---> typeconverter associations.

+1  A: 

On the light frameworks you have limited options; I wouldn't shy away from a little hard-coding, especially if you only need to support the core types. It will also be simpler and faster than the full TypeConverter option. Something like:

    static object Parse(Type type, string s)
    {
        switch (Type.GetTypeCode(type))
        {
            case TypeCode.Boolean: return bool.Parse(s);
            case TypeCode.Byte: return byte.Parse(s);
            case TypeCode.Char: return s[0];
            case TypeCode.DateTime: return DateTime.Parse(s);
                ...
        }
    }
Marc Gravell
Thanks, i was hoping it wouldn't come to this but i guess its not that big of a deal...
luke
A: 

you can get the TypConverter Attribute of your type, then get the property ConverterTypeName, and create the instance of this type, you can cast the instance to type TypeConverter, and then you can use "CanCOnverterTo", "CanConvertFrom","ConvertTo"... and so on, but the problem is that a lot of types does not use TypeCOnverterAttributes, but xaml parser have hard coded implementation of it.. SL sucks really...

[email protected])) , not [email protected]

jinek
A: 

I have built a rather comprehensive toolset to solve this issue. There are many steps involved but here it is:

1) Return the original value if the target type is Assignable from the original value 2) Construct a type converter otherwise (here come the interesting parts)

public static TypeConverter GetTypeConverter(Type type) 
{
   TypeConverterAttribute attribute = (TypeConverterAttribute)Attribute.GetCustomAttribute(type, typeof(TypeConverterAttribute), false);
   if (attribute != null)
   {
     try 
     {
       var converterType = Type.GetType(attribute.ConverterTypeName, false);
       if (converterType != null) 
       {
         return (Activator.CreateInstance(converterType) as TypeConverter);
 }
     }
     catch {}
   }
   return new XamlStringConverter(type);
  }

Nothing marvellous here. But notice the XamlStringConverter returned if no converter was found. It makes use of the Xaml Parser to convert things. The type field is included in the Converter, and contains the type passed to the constructor.

    public override object ConvertFrom(ITypeDescriptorContext context, CultureInfo culture, object value) {
        var strValue = value as string;
        if (strValue != null) {
            if (this.type == typeof(bool)) {
                return bool.Parse(strValue);
            }
            if (this.type.IsEnum) {
                return Enum.Parse(this.type, stringValue, false);
            }
            StringBuilder stringBuilder = new StringBuilder();
            stringBuilder.Append("<ContentControl xmlns='http://schemas.microsoft.com/client/2007' xmlns:c='" + ("clr-namespace:" + this.type.Namespace + ";assembly=" + this.type.Assembly.FullName.Split(new char[] { ',' })[0]) + "'>\n");
            stringBuilder.Append("<c:" + this.type.Name + ">\n");
            stringBuilder.Append(strValue);
            stringBuilder.Append("</c:" + this.type.Name + ">\n");
            stringBuilder.Append("</ContentControl>");
            ContentControl instance = XamlReader.Load(stringBuilder.ToString()) as ContentControl;
            if (instance != null) {
                return instance.Content;
            }
        }
        return base.ConvertFrom(context, culture, value);
    }
Maupertuis