2

As we all know Forms created with Form.cs file

I have property of type Form

example : public Form TargetForm {get;set;}

i don't need to use Activiator.CreateInstance() to create Form I just need to choose a Form from Forms.cs files and attach it with property of TargetForm .

See Screenshot http://prntscr.com/pmuxdd

Tips i guess maybe something usefull to readers : TypeDescriptors, Attributes maybe that return a list of classes in Visual Studio Solutions.

As we all know the ComponentModel API is hard to deal with. so please don't feel bad about that.

Reza Aghaei
  • 120,393
  • 18
  • 203
  • 398
deveton
  • 291
  • 4
  • 26
  • I just answered [this question](https://stackoverflow.com/q/58374499/8967612) a few days ago. It's almost an exact duplicate but it's for VB.NET. The code should be easy enough to convert to C# though. – 41686d6564 stands w. Palestine Oct 23 '19 at 03:17
  • Ahmed, i try everything but it shows empty list of forms http://prntscr.com/pmvbbg – deveton Oct 23 '19 at 04:03

1 Answers1

2

There are two services that can help you at design-time to discover and resolve all types in the solution:

In the other hand, to show standard values in a dropdown in property editor, you can create a TypeConverter:

  • TypeConverter: Provides a unified way of converting types of values to other types, as well as for accessing standard values and subproperties.

Knowing about above options, you can create a custom type converter to discover all form types in the project and list in the dropdown.

Example

In the following example, I've created a custom button class which allows you to select a form type in design type and then at run-time, if you click on the button it shows the selected form as dialog:

enter image description here

To see a VB.NET version for this answer see this post.

MyButton

using System;
using System.ComponentModel;
using System.Windows.Forms;
public class MyButton : Button
{
    [TypeConverter(typeof(FormTypeConverter))]
    public Type Form { get; set; }

    protected override void OnClick(EventArgs e)
    {
        base.OnClick(e);
        if (Form != null && typeof(Form).IsAssignableFrom(Form))
        {
            using (var f = (Form)Activator.CreateInstance(Form))
                f.ShowDialog();
        }
    }
}

FormTypeConverter

using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.ComponentModel.Design;
using System.Globalization;
using System.Linq;
using System.Windows.Forms;
public class FormTypeConverter : TypeConverter
{
    public override bool GetStandardValuesExclusive
        (ITypeDescriptorContext context)
    {
        return true;
    }
    public override bool CanConvertTo
        (ITypeDescriptorContext pContext, Type pDestinationType)
    {
        return base.CanConvertTo(pContext, pDestinationType);
    }
    public override object ConvertTo
        (ITypeDescriptorContext pContext, CultureInfo pCulture,
        object pValue, Type pDestinationType)
    {
        return base.ConvertTo(pContext, pCulture, pValue, pDestinationType);
    }
    public override bool CanConvertFrom(ITypeDescriptorContext pContext,
        Type pSourceType)
    {
        if (pSourceType == typeof(string))
            return true;
        return base.CanConvertFrom(pContext, pSourceType);
    }
    public override object ConvertFrom
        (ITypeDescriptorContext pContext, CultureInfo pCulture, object pValue)
    {
        if (pValue is string)
            return GetTypeFromName(pContext, (string)pValue);
        return base.ConvertFrom(pContext, pCulture, pValue);
    }

    public override bool GetStandardValuesSupported
        (ITypeDescriptorContext pContext)
    {
        return true;
    }
    public override StandardValuesCollection GetStandardValues
        (ITypeDescriptorContext pContext)
    {
        List<Type> types = GetProjectTypes(pContext);
        List<string> values = new List<string>();
        foreach (Type type in types)
            values.Add(type.FullName);

        values.Sort();
        return new StandardValuesCollection(values);
    }
    private List<Type> GetProjectTypes(IServiceProvider serviceProvider)
    {
        var typeDiscoverySvc = (ITypeDiscoveryService)serviceProvider
            .GetService(typeof(ITypeDiscoveryService));
        var types = typeDiscoverySvc.GetTypes(typeof(object), true)
            .Cast<Type>()
            .Where(item =>
                item.IsPublic &&
                typeof(Form).IsAssignableFrom(item) &&
                !item.FullName.StartsWith("System")
            ).ToList();
        return types;
    }
    private Type GetTypeFromName(IServiceProvider serviceProvider, string typeName)
    {
        ITypeResolutionService typeResolutionSvc = (ITypeResolutionService)serviceProvider
            .GetService(typeof(ITypeResolutionService));
        return typeResolutionSvc.GetType(typeName);
    }
}
Reza Aghaei
  • 120,393
  • 18
  • 203
  • 398
  • Thanks Reza, your answers in Component Model are always awesome. please can you inform me how i can be skillful in Type Descriptors and this things ? is there book for that ? and how you deep-knowledge these things. i assume 75 % programmers doesn't know anything in Component Model. Did you debugging Standard Libraries or something :) – deveton Oct 28 '19 at 13:44
  • 1
    You're most welcome :) Most of the things that I know about design-time suppor, I've learned from microsoft documentations and source code of Windows Forms in .Net Framework. – Reza Aghaei Oct 28 '19 at 14:19
  • Execuse me sir, i try this to get only types of custom control i have , http://prntscr.com/pp7l6o it gave empty list – deveton Oct 28 '19 at 14:53
  • 1
    The only thing that you need to change in the code is changing `typeof(Form).IsAssignableFrom(item)` to `typeof(YourUserControl).IsAssignableFrom(item)`. But keep in mind: **(1)** This solution is useful for cases that property is defined as `public Type TheProperty { get; set; }`. In case you want to have a property as `public YourUserControl TheProperty { get; set; }`, in this case without using any `TypeConverter` attribute, the designer will list all instances of `YourUserControl` which you have put on the form. – Reza Aghaei Oct 29 '19 at 03:50
  • 1
    **(2)** Sometimes when you change the designer related classes, you need to close all designer windows and clean and rebuild the solution. **(3)** In some cases you need to close VS and even [clean designer cache](https://stackoverflow.com/a/54724628/3110834). **(4)** In you did all this things but the problem is still there, you may want to [debug designer](https://stackoverflow.com/a/37347549/3110834). – Reza Aghaei Oct 29 '19 at 03:54
  • 1
    No problem. Hope it helps :) – Reza Aghaei Nov 02 '19 at 15:45