【问题标题】:User Control Property that shows a list of all Forms at design time在设计时显示所有表单列表的用户控件属性
【发布时间】:2019-10-23 03:14:19
【问题描述】:

众所周知,使用 Form.cs 文件创建的表单

我有 Form 类型的属性

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

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

见截图http://prntscr.com/pmuxdd

我想可能对读者有用的提示: 类型描述符、属性可能会返回 Visual Studio 解决方案中的类列表。

众所周知,ComponentModel API 很难处理。所以请不要为此感到难过。

【问题讨论】:

  • 我前几天刚回复this question。它几乎完全一样,但它适用于 VB.NET。不过,代码应该很容易转换为 C#。
  • 艾哈迈德,我尝试了所有方法,但它显示了空的表单列表prntscr.com/pmvbbg

标签: c# .net winforms user-controls windows-forms-designer


【解决方案1】:

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

另一方面,要在属性编辑器的下拉列表中显示标准值,您可以创建一个TypeConverter

  • TypeConverter提供一种将值类型转换为其他类型以及访问标准值和子属性的统一方法。

了解上述选项后,您可以创建自定义类型转换器以发现项目中的所有表单类型并在下拉列表中列出。

示例

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

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

我的按钮

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,您在组件模型中的回答总是很棒。请你告诉我如何才能熟练使用类型描述符和这些东西?有书吗?以及你如何深入了解这些事情。我假设 75% 的程序员对组件模型一无所知。你调试标准库还是什么的:)
  • 不客气 :) 我所知道的关于设计时支持的大部分内容,都是从微软文档和 .Net Framework 中 Windows 窗体的源代码中学到的。
  • 您唯一需要在代码中更改的是将typeof(Form).IsAssignableFrom(item) 更改为typeof(YourUserControl).IsAssignableFrom(item)。但请记住:(1) 此解决方案适用于属性定义为 public Type TheProperty { get; set; } 的情况。如果您想拥有public YourUserControl TheProperty { get; set; } 的属性,在这种情况下不使用任何TypeConverter 属性,设计器将列出您在表单上放置的所有YourUserControl 实例。
  • (2) 有时当您更改设计器相关类时,您需要关闭所有设计器窗口并清理并重建解决方案。 (3) 在某些情况下你需要关闭VS甚至clean designer cache(4) 在你做了所有这些事情但问题仍然存在,你可能想debug designer
  • 没问题。希望它有所帮助:)
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 2021-04-19
  • 1970-01-01
  • 1970-01-01
  • 2017-06-27
  • 1970-01-01
  • 2010-09-05
  • 2011-02-15
相关资源
最近更新 更多