如何在UITypeEditor中发现某种类型的所有静态字段?

时间:2014-04-10 11:39:56

标签: c# winforms visual-studio user-controls

我希望使用我的自定义控件的人通过简单的下拉列表选择常量。控件应该是可重用的,因此它驻留在库中,因此它不能访问枚举,并且实际上可以在任何地方定义常量。

问题是AppDomain.CurrentDomain.GetAssemblies()不包含您正在设计的当前项目。当我创建一个单独的项目时,它有时可以工作,但大多数情况下它并没有。并且我没有工作,我的意思是:它无法找到库中定义的任何类/常量,因此它们不会显示在下拉列表中。

其他一切都已经奏效了。下拉列表有效。代码生成是一个但很笨重,但它的工作原理。我总能找到TestControl本身定义的常量。

似乎设计师本身并不总是加载所有可用的组件/项目。那么如何在设计师/视觉工作室本身的环境中加载我需要的项目呢?或者如何在UITypeEditor中引用/查找我的依赖项列表中的其他项目?

我创建了自己的TestControl:

public partial class TestControl : UserControl, IHasTags
{
    public static readonly ITestItem A = new TestItemImpl(null, "A", "Aap");
    public static readonly ITestItem B = new TestItemImpl(null, "B", "B");
    public static readonly ITestItem C_xx = new TestItemImpl(null, "C", "C");
    public static readonly ITestItem D = new TestItemImpl(null, "D", "D");

    [Editor(typeof(ItemEditor), typeof(UITypeEditor))]
    public ITestItem item { get; set; }

    public TestControl()
    {
        InitializeComponent();
    }

}

用我自己的编辑:

public class ItemEditor : UITypeEditor
{
    private IWindowsFormsEditorService _editorService;

    public override UITypeEditorEditStyle GetEditStyle(ITypeDescriptorContext context)
    {
        // drop down mode (we'll host a listbox in the drop down)
        return UITypeEditorEditStyle.DropDown;
    }

    public override object EditValue(ITypeDescriptorContext context, IServiceProvider provider, object value)
    {
        _editorService = (IWindowsFormsEditorService)provider.GetService(typeof(IWindowsFormsEditorService));

        // use a list box
        ListBox lb = new ListBox();
        lb.SelectionMode = SelectionMode.One;
        lb.SelectedValueChanged += OnListBoxSelectedValueChanged;
        lb.Width = 300;

        // get the analytic object from context
        // this is how we get the list of possible benchmarks
        TestControl ctrl = (TestControl)context.Instance;


        // Add all test items
        IList<StaticFieldInfo<ITestItem>> items = ClassHelper.getStaticFields<IHasTags, ITestItem>();
        foreach (StaticFieldInfo<ITestItem> item in items)
        {
            lb.Items.Add(item);
        }

        // show this model stuff
        _editorService.DropDownControl(lb);
        if (lb.SelectedItem == null) // no selection, return the passed-in value as is
            return value;

        StaticFieldInfo<ITestItem> result = (StaticFieldInfo<ITestItem>)lb.SelectedItem;

        return result.value;
    }


    private void OnListBoxSelectedValueChanged(object sender, EventArgs e)
    {
        // close the drop down as soon as something is clicked
        _editorService.CloseDropDown();
    }
}

我使用以下帮助器收集所有常量:

public class StaticFieldInfo<T>
{
    public StaticFieldInfo(FieldInfo fieldInfo, T value)
    {
        this.fieldInfo = fieldInfo;
        this.value = value;
    }
    public T value { get; private set; }
    public FieldInfo fieldInfo { get; private set; }

    public override string ToString()
    {
        return value.ToString() + " (" + fieldInfo.DeclaringType.FullName + "." + fieldInfo.Name + ")";
    }
}

public class ClassHelper
{
    public static IList<StaticFieldInfo<T>> getStaticFields<C, T>()
    {
        Type classType = typeof(C);
        Type fieldType = typeof(T);
        List<StaticFieldInfo<T>> result = new List<StaticFieldInfo<T>>();

        foreach (Assembly asm in AppDomain.CurrentDomain.GetAssemblies())
        {
            try
            {
                foreach (Type t in asm.GetTypes())
                {
                    if (classType.IsAssignableFrom(t))
                    {
                        foreach (FieldInfo f in t.GetFields())
                        {
                            if (f.IsStatic && fieldType.IsAssignableFrom(f.FieldType))
                            {
                                T value = (T)f.GetValue(null);
                                if (value != null)
                                {
                                    result.Add(new StaticFieldInfo<T>(f, value));
                                }
                            }
                        }
                    }
                }
            }
            catch (ReflectionTypeLoadException)
            {
                // Ignore errors
            }
        }

        return result;
    }

}

其余代码(不太重要):

public interface IHasTags
{
}

[TypeConverter(typeof(ITestItemConverter))]
public interface ITestItem
{
    string driver { get; set; }
    string tag { get; set; }
    string name { get; set; }
}


public class ITestItemConverter : TypeConverter
{
    public override bool CanConvertTo(ITypeDescriptorContext context, Type destinationType)
    {
        // we only know how to convert from to a string
        return typeof(string) == destinationType;
    }

    public override object ConvertTo(ITypeDescriptorContext context, CultureInfo culture, object value, Type destinationType)
    {


        if (value != null)
        {
            return value.ToString();
        }

        return "(none)";
    }
}

[DesignerSerializer(typeof(ItemSerializer), typeof(CodeDomSerializer))]
public class TestItemImpl : ITestItem
{
    public TestItemImpl()
    {
    }

    public TestItemImpl(string driver, string tag, string name)
    {
        this.driver = driver;
        this.tag = tag;
        this.name = name;
    }

    public override string ToString()
    {
        return name;
    }

    public string driver { get; set; }

    public string tag { get; set; }

    public string name { get; set; }
}

public class ItemSerializer : CodeDomSerializer
{
    public override object Deserialize(IDesignerSerializationManager manager, object codeObject)
    {


        // This is how we associate the component with the serializer.
        CodeDomSerializer baseClassSerializer = (CodeDomSerializer)manager.
        GetSerializer(typeof(TestItemImpl).BaseType, typeof(CodeDomSerializer));

        /* This is the simplest case, in which the class just calls the base class
            to do the work. */
        return baseClassSerializer.Deserialize(manager, codeObject);
    }

    public override object Serialize(IDesignerSerializationManager manager, object value)
    {
        /* Associate the component with the serializer in the same manner as with
            Deserialize */
        CodeDomSerializer baseClassSerializer = (CodeDomSerializer)manager.
            GetSerializer(typeof(TestItemImpl).BaseType, typeof(CodeDomSerializer));


        object codeObject = baseClassSerializer.Serialize(manager, value);



        /* Anything could be in the codeObject.  This sample operates on a
            CodeStatementCollection. */
        if (codeObject is CodeStatementCollection)
        {
            CodeStatementCollection statements = (CodeStatementCollection)codeObject;

            StaticFieldInfo<ITestItem> field = null;
            foreach (StaticFieldInfo<ITestItem> item in ClassHelper.getStaticFields<IHasTags, ITestItem>())
            {
                if (value == item.value)
                {
                    field = item;
                    break;
                }
            }

            // If field can be found (should be always)
            if (field != null)
            {
                statements = new CodeStatementCollection();
                statements.Add(new CodeSnippetExpression(typeof(ITestItem).FullName + "  " + this.GetUniqueName(manager, value) + " = " + typeof(TestControl).FullName + "." + field.fieldInfo.Name));

                codeObject = statements;
            }
        }
        return codeObject;
    }
}

0 个答案:

没有答案