C# 显示设计时所有窗体列表的用户控件属性

C# 显示设计时所有窗体列表的用户控件属性,c#,.net,winforms,user-controls,windows-forms-designer,C#,.net,Winforms,User Controls,Windows Forms Designer,我们都知道使用Form.cs文件创建的表单 我的属性类型为Form 示例:public Form TargetForm{get;set;} 我不需要使用Activator.CreateInstance()来创建表单 我只需要从Forms.cs文件中选择一个表单,并将其附加到TargetForm属性 见截图 小贴士我想可能对读者有用: 类型描述符、属性,可能返回VisualStudio解决方案中的类列表 众所周知,组件模型API很难处理。因此,请不要为此感到难过。有两项服务可以帮助您在设计时发现并

我们都知道使用Form.cs文件创建的表单

我的属性类型为
Form

示例:
public Form TargetForm{get;set;}

我不需要使用Activator.CreateInstance()来创建表单 我只需要从Forms.cs文件中选择一个表单,并将其附加到TargetForm属性

见截图

小贴士我想可能对读者有用: 类型描述符、属性,可能返回VisualStudio解决方案中的类列表


众所周知,组件模型API很难处理。因此,请不要为此感到难过。

有两项服务可以帮助您在设计时发现并解决解决方案中的所有类型:

  • :在设计时发现可用类型

  • :提供按名称检索程序集或类型的接口

另一方面,要在属性编辑器中的下拉列表中显示标准值,可以创建
类型转换器

  • :提供将值类型转换为其他类型以及访问标准值和子属性的统一方法
了解上述选项后,您可以创建自定义类型转换器来发现项目中的所有表单类型,并在下拉列表中列出

示例

在下面的示例中,我创建了一个自定义按钮类,该类允许您在“设计类型”中选择一个表单类型,然后在运行时,如果单击该按钮,它会将所选表单显示为对话框:

要查看此答案的VB.NET版本,请参阅

我的按钮

模板转换器

使用系统;
使用System.Collections.Generic;
使用系统组件模型;
使用System.ComponentModel.Design;
利用制度全球化;
使用System.Linq;
使用System.Windows.Forms;
公共类FormTypeConverter:TypeConverter
{
公共覆盖布尔GetStandardValues结论
(ITypeDescriptorContext上下文)
{
返回true;
}
公共覆盖布尔CanConvertTo
(ITypeDescriptorContext pContext,类型pDestinationType)
{
return base.CanConvertTo(pContext,pDestinationType);
}
公共覆盖对象转换为
(ITypeDescriptorContext pContext,CultureInfo pCulture,
对象pValue,类型pDestinationType)
{
返回base.ConvertTo(pContext、pCulture、pValue、pDestinationType);
}
公共覆盖布尔CanConvertFrom(ITypeDescriptorContext pContext,
类型pSourceType)
{
if(pSourceType==typeof(string))
返回true;
return base.CanConvertFrom(pContext,pSourceType);
}
公共重写对象转换自
(ITypeDescriptorContext pContext,CultureInfo pCulture,object pValue)
{
if(pValue是字符串)
返回GetTypeFromName(pContext,(string)pValue);
返回base.ConvertFrom(pContext、pCulture、pValue);
}
支持公共覆盖布尔GetStandardValues
(ITypeDescriptorContext pContext)
{
返回true;
}
公共覆盖标准值集合GetStandardValues
(ITypeDescriptorContext pContext)
{
列表类型=GetProjectTypes(pContext);
列表值=新列表();
foreach(类型中的类型)
value.Add(type.FullName);
value.Sort();
返回新的标准值集合(值);
}
私有列表GetProjectTypes(IServiceProvider服务提供商)
{
var typeDiscoverySvc=(ITypeDiscoveryService)服务提供者
.GetService(类型of(ITypeDiscoveryService));
var types=typeDiscoverySvc.GetTypes(typeof(object),true)
.Cast()
。其中(项目=>
item.IsPublic&&
类型(表格)。IsAssignableFrom(项目)&&
!item.FullName.StartsWith(“系统”)
).ToList();
返回类型;
}
私有类型GetTypeFromName(IServiceProvider服务提供程序,字符串类型名称)
{
ITypeResolutionService typeResolutionSvc=(ITypeResolutionService)服务提供商
.GetService(类型of(ITypeResolutionService));
返回typeResolutionSvc.GetType(typeName);
}
}

我几天前刚刚回答。这几乎是一个完全相同的版本,但它是为VB.NET设计的。代码应该很容易转换成C语言。艾哈迈德,我尝试了所有的方法,但是它显示了空的表单列表。谢谢雷扎,你在组件模型中的回答总是很棒的。请你告诉我,我如何能熟练的类型描述符和这件事?有那本书吗?以及你对这些事情的深刻认识。我假设75%的程序员对组件模型一无所知。你调试过标准库吗:)非常欢迎:)我知道的关于设计时支持的大部分内容。或者,我从microsoft文档和.Net Framework中Windows窗体的源代码中学到了。在代码中,你只需要更改
typeof(Form)。IsAssignableFrom(item)
类型(您的用户控件)。IsAssignableFrom(项目)
。但请记住:(1)此解决方案适用于将属性定义为
公共类型属性{get;set;}
的情况。如果您希望将属性作为
public YourUserControl属性{get;set;}
,在这种情况下,不使用任何
TypeConverter
属性,设计器将列出您在表单上放置的
YourUserControl
的所有实例。(2)有时,当您更改与设计器相关的类时,您需要关闭所有设计器窗口,清理并重新生成解决方案。(3) 在某些情况下,您需要关闭VS甚至。(4) 事实上,你做了所有这些事情,但问题仍然存在,你可能想要。没问题。希望有帮助:)
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();
        }
    }
}
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);
    }
}