Type Converter not appearing in Designer

Posts   
 
    
blarg
User
Posts: 27
Joined: 27-Nov-2007
# Posted on: 03-Dec-2007 04:36:52   

I have a .NET type that knows how to serialize to and from a byte[]. I'm trying to write a Type Converter that would allow me to use the type directly in the application as opposed to having to call the serialize and deserialize methods manually.

I've looked at the source code for the Boolean type converter, as well as the example enum converter here: http://www.llblgen.com/TinyForum/Messages.aspx?ThreadID=7355

Here's an excerpt of the code I currently have with the implementation details removed:

[Description("Converter for mapping a Recurrence to a byte[] field.")]
    public class RecurrenceTypeConverter : TypeConverter
    {
        public RecurrenceTypeConverter()
        {
        }

        public override bool CanConvertFrom(ITypeDescriptorContext context, Type sourceType)
        {
            switch (sourceType.FullName)
            {
                case "System.Byte[]":
                    return true;
                default:
                    return false;
            }
        }

        public override bool CanConvertTo(ITypeDescriptorContext context, Type destinationType)
        {
            switch (destinationType.FullName)
            {
                case "System.Byte[]":
                    return true;
                default:
                    return false;
            }
        }

        public override object ConvertFrom(ITypeDescriptorContext context, CultureInfo culture, object value)
        {
            if (!(value is byte[]))
            {
                throw new NotSupportedException("Only System.Byte[] may be converted using this converter.");
            }

            return Recurrence.Deserialize(value as byte[]);
        }

        public override object ConvertTo(ITypeDescriptorContext context, CultureInfo culture, object value, Type destinationType)
        {
            if (!(value is Recurrence) || destinationType != typeof(byte[]))
            {
                throw new ArgumentException("Either the source type or destination type are not supported by this converter.");
            }

            Recurrence recurrence = value as Recurrence;

            return recurrence.Serialize();
        }

        public override object CreateInstance(ITypeDescriptorContext context, IDictionary propertyValues)
        {
            return new Recurrence();
        }
    }

LLBLGen Pro Version 2.5 Final Runtime libraries version: 2.5 Using Microsoft SQL Server 2000 and 2005

The thing that confuses me about these is shouldn't one of the either from or to types be my custom type? Why are both "to" and "from" types numeric in the bool example? Wouldn't one of them be the boolean?

When I select a field that has a .NET type of System.Byte[] in the LLBL designer, the "Use different .NET type" drop down box is disabled. I know I'm putting the dll in the right place (c:\Program Files\Solutions Design\LLBLGen Pro v2.5\TypeConverters) because when I try to copy over it while the designer is open it's in use.

What am I missing and/or how can I debug the "should I use this type converter in the combo box" code? The converter is in a dll with a bunch of other code. Would putting it in its own dll help?

daelmo avatar
daelmo
Support Team
Posts: 8245
Joined: 28-Nov-2005
# Posted on: 03-Dec-2007 05:23:09   

blarg wrote:

The thing that confuses me about these is shouldn't one of the either from or to types be my custom type? Why are both "to" and "from" types numeric in the bool example? Wouldn't one of them be the boolean?

At the **ConvertFrom **method, it receives a _numeric _and returns a boolean. At the **ConvertTo **method, it receives a _boolean _and returns a numeric

Here are the resumed documentation for that virtual methods:

// Summary:
//   Returns whether this converter can convert an object of the given type to
//   the type of this converter.
public virtual bool CanConvertFrom(ITypeDescriptorContext context, Type sourceType);

// Summary:
//   Returns whether this converter can convert an object of the given type to
//   the type of this converter, using the specified context.
public virtual bool CanConvertFrom(ITypeDescriptorContext context, Type sourceType);

// Summary:
//   Converts the given object to the type of this converter, using the specified
//   context and culture information.
public virtual object ConvertFrom(ITypeDescriptorContext context, CultureInfo culture, object value);

// Summary:
//   Converts the given value object to the specified type, using the specified
//   context and culture information.
public virtual object ConvertTo(ITypeDescriptorContext context, CultureInfo culture, object value, Type destinationType);

blarg wrote:

When I select a field that has a .NET type of System.Byte[] in the LLBL designer, the "Use different .NET type" drop down box is disabled. I know I'm putting the dll in the right place (c:\Program Files\Solutions Design\LLBLGen Pro v2.5\TypeConverters) because when I try to copy over it while the designer is open it's in use.

Are you sure you are copying the correct DLL (bin/Debug)? I tested your converter and I can't use it at Designer.

David Elizondo | LLBLGen Support Team
blarg
User
Posts: 27
Joined: 27-Nov-2007
# Posted on: 03-Dec-2007 23:58:48   

daelmo wrote:

At the **ConvertFrom **method, it receives a _numeric _and returns a boolean. At the **ConvertTo **method, it receives a _boolean _and returns a numeric

Yup, that's fine. The ConvertFrom method I posted receives a byte[], and returns a subclass of Recurrance. The ConvertTo methods receives a subclass of Recurrence and returns a byte[].

daelmo wrote:

Are you sure you are copying the correct DLL (bin/Debug)?

Yup. That's one thing I'm sure of.

daelmo wrote:

I tested your converter and I can't use it at Designer.

I can't either. So what am I doing that's preventing it from being used in the designer? For now we really could have convert from and convert to just return hard coded values if that would make it easier to debug. Once I can get the code to be called, then I'll be set.

In fact if you can make a converter that turns a byte[] into anything else (maybe a string for example), then that might show me where I've gone wrong.

Also it might be worth mentioning that Recurrence is an abstract base class that manufactures specific instances depending on the data it's deserialising.

daelmo avatar
daelmo
Support Team
Posts: 8245
Joined: 28-Nov-2005
# Posted on: 04-Dec-2007 00:36:36   

blarg wrote:

daelmo wrote:

I tested your converter and I can't use it at Designer.

I can't either.

Sorry, I meant: I CAN. I tested, removing your specific lines (where you use Recurrence) and I can use it at the LLBLGen Designer.

I didn't write any extra code. I'm just returning default values instead of your Recurrence instances. I will see if I can send you an example with this (could you provide me your email address?)

David Elizondo | LLBLGen Support Team
blarg
User
Posts: 27
Joined: 27-Nov-2007
# Posted on: 04-Dec-2007 01:29:05   

daelmo wrote:

could you provide me your email address?)

<email address edited out>

Thanks!

daelmo avatar
daelmo
Support Team
Posts: 8245
Joined: 28-Nov-2005
# Posted on: 04-Dec-2007 08:30:08   

Sent!

David Elizondo | LLBLGen Support Team
blarg
User
Posts: 27
Joined: 27-Nov-2007
# Posted on: 05-Dec-2007 02:28:00   

daelmo wrote:

Sent!

I've played with the sample you sent me. It shows up just fine in the designer as you sent it through.

I then take the file, put it in my library DLL, and then put that into the Type Converters directory. Nothing. The only thing that I'm modifying in the file is the namespace when I move it into the library.

It's looking like I'm going to have to give this type its own DLL.

blarg
User
Posts: 27
Joined: 27-Nov-2007
# Posted on: 05-Dec-2007 07:32:03   

Alright, I've looked into this some more.

Is LLBL still using this code to look through assemblies? The .Net Reflector thinks so.

/// <summary>
/// Processes the assembly for type converters.
/// </summary>
/// <param name="toProcess">To process.</param>
/// <param name="toFill">To fill.</param>
internal static void ProcessAssemblyForTypeConverters(Assembly toProcess, Hashtable toFill)
{
    Type[] types = toProcess.GetTypes();
    foreach(Type currentType in types)
    {
        if(currentType.IsSubclassOf(typeof(TypeConverter)) && !currentType.IsAbstract)
        {
            // found a typeConverter type
            TypeConverter converter = (TypeConverter)toProcess.CreateInstance(currentType.FullName);
            if(converter==null)
            {
                continue;
            }
            TypeConverterDefinition converterDefinition = new TypeConverterDefinition();
            converterDefinition.AssemblyName = toProcess.FullName;
            converterDefinition.ConverterInstance = converter;
            converterDefinition.TypeFullName = currentType.FullName;
            // get description
            object[] attributes = currentType.GetCustomAttributes(typeof(DescriptionAttribute), true);
            if(attributes.Length>0)
            {
                converterDefinition.Description = ((DescriptionAttribute)attributes[0]).Description;
            }

            toFill.Add(currentType.FullName, converterDefinition);
        }
    }
}

I created a unit test with this code which pulls the type converter successfully even when it's in my library. I then put that same DLL into the type converters directory and it doesn't show anything in the designer.

I moved the type converter and this type off into its own project and now LLBL's fine with it all. Seems like there might be some type it's finding in my library that it dislikes and throws an error on, which then stops all the processing. Specifically, the code has a problem when a class is a TypeConverter, but doesn't allow an instance to be created directly with CreateInstance.

I found for example that if it went to probe some of the system DLLs, it'd throw a method missing exception when it tries to instantiate an instance to determine type at the toProcess.CreateInstance line (which in my unit test was line 49). If you're curious, here's a stack trace:

   at System.RuntimeType.CreateInstanceImpl(BindingFlags bindingAttr, Binder binder, Object[] args, CultureInfo culture, Object[] activationAttributes)
   at System.Activator.CreateInstance(Type type, BindingFlags bindingAttr, Binder binder, Object[] args, CultureInfo culture, Object[] activationAttributes)
   at System.Reflection.Assembly.CreateInstance(String typeName)
   at [My Unit Test]:line 49

Might be worth wrapping that particular line with a try {} catch { continue; } so that even if it doesn't like a particular type, it doesn't give up and stop looking entirely. I think that'd fix the problem I'm having with the designer when it's in the library.

But for the moment I've worked around the issue by creating a separate DLL. Thanks again for all your help so far.

Otis avatar
Otis
LLBLGen Pro Team
Posts: 39894
Joined: 17-Aug-2003
# Posted on: 05-Dec-2007 12:30:14   

It doesn't probe system dlls only dlls in the folders specified as folders for typeconverters.

It indeed gives up after an error in the dll. I could add code which could filter out faulty typeconverters, but is that really necessary? I mean: the type converters should obey the rules specified, if they don't do that, they're meaningless for llblgen pro anyway, and the idea is that you write specific type converters for llblgen pro code anyway, so IMHO it's not that much of a problem. If you could elaborate a bit more on why you would have 1 or more typeconverter classes in the dll which simply won't work, I'll likely better understand the necessity of the code change simple_smile

Frans Bouma | Lead developer LLBLGen Pro
blarg
User
Posts: 27
Joined: 27-Nov-2007
# Posted on: 05-Dec-2007 23:53:16   

Otis wrote:

It doesn't probe system dlls only dlls in the folders specified as folders for typeconverters.

Yes, I understand that. The problem is when you have a massive library dll.

Otis wrote:

If you could elaborate a bit more on why you would have 1 or more typeconverter classes in the dll which simply won't work, I'll likely better understand the necessity of the code change simple_smile

Type converters don't have to be able to instantiate an instance to "work." I brought up the system dll because obviously Microsoft is writing type converters that can't instantiate instances. Sure, they won't work with LLBL, which is why you'd ignore them, but they would work on their own and for their own reasons.

Microsoft says: To support custom type conversion, override the CanConvertFrom, CanConvertTo, ConvertFrom, and ConvertTo methods.

There are plenty of reasons one might have a general "library" type dll that would include type converters not meant to work with LLBL. IMHO it'd be nice if we weren't forced to refactor the LLBL stuff out into another reference to include in our projects.

Sure, you could force people to make a new dll, but I don't see why it would be so bad to pull everything that would work for LLBL out of the dll while leaving those that won't off the menu.

I guess I'm wondering what's wrong with continuing the search if you come across a type that won't work.

Otis avatar
Otis
LLBLGen Pro Team
Posts: 39894
Joined: 17-Aug-2003
# Posted on: 06-Dec-2007 11:22:17   

Ok, good point. I'll add a change request for this to v2.6.

Frans Bouma | Lead developer LLBLGen Pro
blarg
User
Posts: 27
Joined: 27-Nov-2007
# Posted on: 10-Dec-2007 02:04:32   

Otis wrote:

Ok, good point. I'll add a change request for this to v2.6.

That'd be great. Thanks! :-)