Windows Develop Bookmark and Share   
 index > Windows Forms Designer > Design Time Reflection
 

Design Time Reflection

Hello.

I'm creating a custom control with desing time support.

For a property MyItems that is a collection of BaseItem's, I need to allow the user to add as many items he wish on a form I created (all in design time).

The problem: I have a number of classes that derived from BaseItem, and I want that the user will be able to select from a combobox all optional elements by using reflection of some sort, so that we I create a new BaseItem derived class, I don't want to change the combobox.

How can I do it?

Eli Gazit  Thursday, December 29, 2005 8:37 AM

Hey Eli,

You can iterate over all the types in an assembly and check inheritance and all with IsAssignableFrom and IsSubClassOf. Here's a piece from our library that does the stuff that you request. Use FindDerivedTypes.



    public static class TypeTools
    {
        private static void AddReferencedAssemblies(
            Hashtable nameToAssemblyMap, Assembly parent, bool deep )
        {
            ArrayList loadedAssemblies = new ArrayList();

            foreach( AssemblyName assemblyName in parent.GetReferencedAssemblies() )
            {
                if( !nameToAssemblyMap.Contains( assemblyName.FullName) )
                {
                    Assembly child = Assembly.Load( assemblyName );
                    nameToAssemblyMap.Add( assemblyName.FullName, child );
                    loadedAssemblies.Add( child );
                }
            }

            if( deep )
            {
                foreach( Assembly child in loadedAssemblies )
                {
                    AddReferencedAssemblies( nameToAssemblyMap, child, deep );
                }
            }
        }

        public static ICollection GetReferencedAssemblies( Assembly root, bool deep )
        {
            Hashtable nameToAssemblyMap = new Hashtable();
            nameToAssemblyMap.Add( root.FullName, root );
           
            if( deep )
            {
                AddReferencedAssemblies( nameToAssemblyMap, root, deep );
            }
           
            return nameToAssemblyMap.Values;
        }

        public static Type[] FindDerivedTypes( Type type, Assembly root, bool deep )
        {
            ArrayList result = new ArrayList();

            ICollection assemblies = GetReferencedAssemblies( root, deep );
            foreach( Assembly assembly in assemblies )
            {
                foreach( Type subType in assembly.GetTypes() )
                {
                    if( type.IsAssignableFrom( subType ) && !subType.IsAbstract )
                    {
                        result.Add( subType );
                    }
                }
            }

            return (Type[]) result.ToArray( typeof( Type ) );
           
        }
        public static Type[] FindDerivedTypes( Type type )
        {
            return FindDerivedTypes( type, Assembly.GetEntryAssembly(), true );
        }
}


 

Oh... and credit to my collegue Peter Verswyvelen who build this code .

Jelle van der Beek2  Thursday, December 29, 2005 2:01 PM
Ah, right. With the type, use Activator.CreateInstance to create the type.
Jelle van der Beek2  Friday, December 30, 2005 9:29 AM

Hey Eli,

You can iterate over all the types in an assembly and check inheritance and all with IsAssignableFrom and IsSubClassOf. Here's a piece from our library that does the stuff that you request. Use FindDerivedTypes.



    public static class TypeTools
    {
        private static void AddReferencedAssemblies(
            Hashtable nameToAssemblyMap, Assembly parent, bool deep )
        {
            ArrayList loadedAssemblies = new ArrayList();

            foreach( AssemblyName assemblyName in parent.GetReferencedAssemblies() )
            {
                if( !nameToAssemblyMap.Contains( assemblyName.FullName) )
                {
                    Assembly child = Assembly.Load( assemblyName );
                    nameToAssemblyMap.Add( assemblyName.FullName, child );
                    loadedAssemblies.Add( child );
                }
            }

            if( deep )
            {
                foreach( Assembly child in loadedAssemblies )
                {
                    AddReferencedAssemblies( nameToAssemblyMap, child, deep );
                }
            }
        }

        public static ICollection GetReferencedAssemblies( Assembly root, bool deep )
        {
            Hashtable nameToAssemblyMap = new Hashtable();
            nameToAssemblyMap.Add( root.FullName, root );
           
            if( deep )
            {
                AddReferencedAssemblies( nameToAssemblyMap, root, deep );
            }
           
            return nameToAssemblyMap.Values;
        }

        public static Type[] FindDerivedTypes( Type type, Assembly root, bool deep )
        {
            ArrayList result = new ArrayList();

            ICollection assemblies = GetReferencedAssemblies( root, deep );
            foreach( Assembly assembly in assemblies )
            {
                foreach( Type subType in assembly.GetTypes() )
                {
                    if( type.IsAssignableFrom( subType ) && !subType.IsAbstract )
                    {
                        result.Add( subType );
                    }
                }
            }

            return (Type[]) result.ToArray( typeof( Type ) );
           
        }
        public static Type[] FindDerivedTypes( Type type )
        {
            return FindDerivedTypes( type, Assembly.GetEntryAssembly(), true );
        }
}


 

Oh... and credit to my collegue Peter Verswyvelen who build this code .

Jelle van der Beek2  Thursday, December 29, 2005 2:01 PM

Hi Jelle, great code, as always.

One question due,

I want to get the classes from a specifiec namespace on my project.

I guess its in the Assembly.GetEntryAssembly(), but how excatly I do it?

 

Eli Gazit  Thursday, December 29, 2005 7:14 PM

Thanks man!

I think you will have to add a bit of code to FindDerivedTypes. Something like this:



        public static Type[] FindDerivedTypes( Type type, Assembly root, bool deep, string namespace )
        {
            ArrayList result = new ArrayList();
            ICollection assemblies = GetReferencedAssemblies( root, deep );
            foreach( Assembly assembly in assemblies )
            {
                foreach( Type subType in assembly.GetTypes() )
                {
                    if( type.IsAssignableFrom( subType ) && !subType.IsAbstract && subType.Namespace == namespace )
                    {
                        result.Add( subType );
                    }
                }
            }

            return (Type[]) result.ToArray( typeof( Type ) );
           
        }


 

Could you try that?

Jelle van der Beek2  Thursday, December 29, 2005 7:22 PM

I'll try, but before that, another problem:

when using:

Reflection.TypeTools.FindDerivedTypes(typeof(Form));

on run time, its fine.

But, on design time, it throws Exception object not set bla bla, I trace it back to the command:

Assembly.GetEntryAssembly()

which in desing time returns null.

Do you know why?

Eli Gazit  Thursday, December 29, 2005 8:13 PM

Don't know why atm. I hope I'll finally get my machine back tomorrow. I'll get back to you about this unless you figure it out yourself in the meantime.

Jelle van der Beek2  Thursday, December 29, 2005 8:16 PM

Ok, got it:

for desing time, I should use:

Assembly.GetExecutingAssembly()

and not:

Assembly.GetEntryAssembly()

this is because the first assembly returns the code that is currently excuting while the second one gets the process excutable, so it will not work an desing time, no excutable...

Thanx for the help

p.s

nice of you to give a sample with variable name: namespace....

 

Eli Gazit  Thursday, December 29, 2005 8:24 PM

 eligazit wrote:

nice of you to give a sample with variable name: namespace....

 

lol! sorry bout that haha.

glad you fixed it. I'll mark it as answered.

Jelle van der Beek2  Thursday, December 29, 2005 8:33 PM

Last one for tongiht...

I've got the type now, how can I create the class from it?

Type t = .... got the type I want to create;

BaseItem item = new <t>();

Where BaseItem is the base class for t, always.

 

 

Eli Gazit  Thursday, December 29, 2005 10:01 PM
Ah, right. With the type, use Activator.CreateInstance to create the type.
Jelle van der Beek2  Friday, December 30, 2005 9:29 AM

You can use google to search for other answers

Custom Search

More Threads

• custom DataGridViewColumnCollectionDialog
• Need help with CodeDomSerializer
• Visual Studio Design Time support for custom controls using Microsoft.WindowsCE.Forms.dll
• Combobox
• Form Controls toolbar
• Form Designer is editing form on open
• How to Add UserControl as TreeNode
• Opening already created form in MDIParent in VB.NET
• Include the parent control when a child is cut / copied and pasted.
• Vertically Oriented Tab Pages