Here you go: Enum type converter example

Posts   
 
    
alexdresko
User
Posts: 336
Joined: 08-Jun-2004
# Posted on: 24-Aug-2006 22:58:53   

LLBLGen only comes with a boolean type converter, but I wanted to map one of my int database fields to an enum in my project.

The first thing I did was create a new class library project in my solution and set the output directory of this project to be "C:\Program Files\Solutions Design\LLBLGen Pro v2.0\TypeConverters"

The main application project already contained the following enum (I renamed the namespaces, types and values to be more generic for this example. You will obviously want to replace YourNamespace and YourEnumType with more appropriate values):


namespace YourNamespace
{
    public enum YourEnumType: int
    {
        ADefaultValue = 0,
        AnotherValue = 1,
        YouGetTheIdea = 2
    }
}

To make this enum available to the type converter, you should add a reference from the main application project to the type converter project. (Truthfully, I don't actually know if adding this reference will work becasue I'm working on an ASP.NET v2 project and therefore can't make this reference... for the time being, I moved the enum above to my type converter project)

I then added a new class to the type converter project with the following code:


using System;
using System.Collections.Generic;
using System.Text;
using System.ComponentModel;

namespace YourNamespace.TypeConverters
{

    public class YourTypeConverter : TypeConverter
    {
        public YourTypeConverter ()
        {
        }

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

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

        public override object ConvertFrom( ITypeDescriptorContext context, System.Globalization.CultureInfo culture, object value )
        {
            YourNamespace.YourEnumType yourEnum = YourNamespace.YourEnumType.ADefaultValue;
                    

            switch ( value.GetType().FullName )
            {
                case "System.Int32":
                case "System.Int16":
                    yourEnum = (YourNamespace.YourEnumType)Enum.ToObject( typeof( YourNamespace.YourEnumType), (int)value );
                    break;
                default:
                    throw new NotSupportedException( "Conversion from a value of type '" + value.GetType().ToString() + "' to YourNamespace.YourEnumType isn't supported" );
            }

            return status;
        }

        public override object ConvertTo( ITypeDescriptorContext context, System.Globalization.CultureInfo culture, object value, Type destinationType )
        {
            if ( value == null )
            {
                throw new ArgumentNullException( "value", "Value can't be null" );
            }

            if ( !( value is YourNamespace.YourEnumType) )
            {
                throw new ArgumentException( "Value isn't of type YourNamespace.YourEnumType", "value" );
            }

            YourNamespace.YourEnumType yourEnum = (YourNamespace.YourEnumType)value;

            switch ( destinationType.FullName )
            {
                case "System.Int32":
                    return (int)yourEnum;
                case "System.Int16":
                    return (short)yourEnum;
                default:
                    throw new NotSupportedException( "Conversion to a value of type '" + destinationType.ToString() + "' isn't supported" );
            }
        }


        public override object CreateInstance( ITypeDescriptorContext context, System.Collections.IDictionary propertyValues )
        {
            return YourNamespace.YourEnumType.ADefaultValue;
        }

    }
}

Now, make sure LLBLGen is shutdown and compile your solution. If successful, you should be able to open LLBLGen again and set any of your int fields to use the type converter. To do this, right click on an entity in LLBLGen and select "Edit / Properties". Then, on the "Mapped entity fields" tab, select a field and look below for the "Use different .NET type" drop down list. This drop down list should contain an entry for your type converter. Select it and press the "Set" button.

Generate that sucker and switch back to your VS solution. To make everything work right, you've got to add a reference from your type converter project to both your DatabaseSpecific and DatabaseGeneric projects (Note, I'm using the adapter framework in my solution and both the specific and generic projects are part of my solution.)

That's it! You should be able to compile the your LLBLGen projects again and use your entities with the enum attached to them. It works great and was easy to do! In fact, it took three times longer to write this post than it did to create and test the type converter!

Have fun and let me know if you run into any problems. I wrote most of this from memory after I finished, so it's possible I forgot something.

bclubb
User
Posts: 934
Joined: 12-Feb-2004
# Posted on: 25-Aug-2006 02:59:16   

Thanks for the contribuition. This is definately a functionality that many people have inquired about since type converters were introduced.

Otis avatar
Otis
LLBLGen Pro Team
Posts: 39613
Joined: 17-Aug-2003
# Posted on: 25-Aug-2006 10:56:09   

Cool contribution, Alex! smile

Frans Bouma | Lead developer LLBLGen Pro
Kris
User
Posts: 79
Joined: 27-Oct-2005
# Posted on: 25-Aug-2006 16:27:59   

Nice contribution. I'm gonna use this one. wink

alexdresko
User
Posts: 336
Joined: 08-Jun-2004
# Posted on: 25-Aug-2006 17:13:55   

Awww shucks.. it's only like 50 lines of code that's mostly copy/pasted from the boolean type converter sample. simple_smile

alexdresko
User
Posts: 336
Joined: 08-Jun-2004
# Posted on: 25-Aug-2006 19:24:06   

Fixed a small typo I introduced while converting the type and variable names..

jspanocsi
User
Posts: 145
Joined: 04-Mar-2005
# Posted on: 25-Aug-2006 20:55:28   

I implemented this for a field in my app. It's works great, except it killed 2 way databinding. It only works one way now (entity to combo box) but when you pick something else in the combo and tab off, it goes back to what it was. Any ideas on how to fix that?

Thanks!

alexdresko
User
Posts: 336
Joined: 08-Jun-2004
# Posted on: 25-Aug-2006 21:16:49   

jspanocsi wrote:

I implemented this for a field in my app. It's works great, except it killed 2 way databinding. It only works one way now (entity to combo box) but when you pick something else in the combo and tab off, it goes back to what it was. Any ideas on how to fix that?

Thanks!

Frans, for the record, jspanocsi in the next cubicle over from me so this is a question for you.

jarod725 avatar
jarod725
User
Posts: 2
Joined: 18-Jan-2007
# Posted on: 18-Jan-2007 16:56:55   

Fyi, it appears that you also need to direct the output of the project containing the enum definition to %LLBL-InstallDir%/TypeConverters. This was moot in your case since your enum was packaged with the converter. wink

Otis avatar
Otis
LLBLGen Pro Team
Posts: 39613
Joined: 17-Aug-2003
# Posted on: 20-Jan-2007 00:51:36   

jarod725 wrote:

Fyi, it appears that you also need to direct the output of the project containing the enum definition to %LLBL-InstallDir%/TypeConverters. This was moot in your case since your enum was packaged with the converter. wink

Could you explain that a bit please?

Frans Bouma | Lead developer LLBLGen Pro
Posts: 17
Joined: 12-Mar-2007
# Posted on: 08-Jul-2008 21:21:55   

How about this one? It works for any enumeration, you just need to declare a type like so:

public class MyEnumConverter : EnumerationConverter<MyEnum> {}

    public abstract class EnumerationConverter<T> : TypeConverter
    {
        private readonly IList<Type> _validTypes = new[] {typeof(byte), typeof(short), typeof(int), typeof(long)};

        public override bool CanConvertFrom(ITypeDescriptorContext context, Type sourceType)
        {
            if (sourceType == null)
            {
                throw new ArgumentNullException("sourceType");
            }

            return _validTypes.Contains(sourceType);
        }

        public override bool CanConvertTo(ITypeDescriptorContext context, Type destinationType)
        {
            if (destinationType == null)
            {
                throw new ArgumentNullException("destinationType");
            }
            return _validTypes.Contains(destinationType);
        }

        public override object ConvertFrom(ITypeDescriptorContext context, CultureInfo culture, object value)
        {
            if (value == null)
            {
                throw new ArgumentNullException("value");
            }
            if (_validTypes.Contains(value.GetType()))
            {
                return Enum.ToObject(typeof(T), value);
            }
            throw new NotSupportedException();
        }

        public override object ConvertTo(ITypeDescriptorContext context,
                                         CultureInfo culture,
                                         object value,
                                         Type destinationType)
        {
            if (destinationType == null)
            {
                throw new ArgumentNullException("destinationType");
            }
            if (value == null)
            {
                throw new ArgumentNullException("value");
            }
            Debug.Assert(value is T);
            return Convert.ChangeType(value, destinationType, culture ?? CultureInfo.InvariantCulture);
        }

        public override object CreateInstance(ITypeDescriptorContext context, IDictionary propertyValues)
        {
            return default(T);
        }
    }

Requires .NET 3.5/C# 3.0 (someone may be willing to make a version compatible with 2.0).

edalzell
User
Posts: 44
Joined: 27-May-2008
# Posted on: 25-May-2009 21:52:07   

Removed by head-in-the-clouds-poster