2

好的,我已经阅读了一些关于使用 PropertyGrid 和集合的问题。但是,我很难理解如何/如果[TypeConverter]对我有用。我读过 MSDN 放出的那段小广告,坦率地说,对于这个可怜的自学成才的程序员来说,这有点欠缺。

所以,这就是我所拥有的。首先是一个集合:

[Serializable]
public List<ModuleData> Modules
{ get { return modules; } }

private List<ModuleData> modules;

集合中的对象:

[Serializable]
internal class ModuleData : IEquatable<ModuleData>
{
    // simple data class with public properties
    // to display in the propgrid control
}

我有一个 ListView 控件,其中包含描述 ModuleData 对象和 BatchData 对象的项目。当我从 ListView 中选择一个 BatchData 项时,PropertyGrid 将按预期显示集合编辑器。有没有办法将集合编辑器限制为仅在 ListView 控件中列出的任何 ModuleData 项?理想情况下,我不希望将 BatchData 项(来自 ListView)添加到 BatchData 集合中 - 特别是因为集合不是 BatchData 对象类型的“类型化”。

如果需要任何进一步的代码示例,我将非常乐意编辑其中的一些片段。

为清楚起见,ModuleData 是一个自定义类,它保存在指定程序集中实例化类所需的数据。它包含的只是字段和公共/内部属性。我想做的是使用与属性网格控件组装的集合编辑器将 ModuleData 对象添加到 BatchDataModule集合。符合添加条件的 ModuleData 对象列在 ListView 控件中。

编辑:删除了: List<ModuleData>继承。

更新:如果我要创建自定义集合编辑器,这是否意味着我正在构建自己的自定义表单/对话框?然后基本上为propertygrid提供信息以通过UITypeEditor的属性和继承来显示我的自定义集合对话框?

4

1 回答 1

4

首先,我有点不确定为什么它既继承(: List<ModuleData>)又包装(public List<ModuleData> Modules { get { return this; } })一个列表——单独一个应该没问题。

然而!要定义您可以创建的新对象的类型,您需要从该属性派生CollectionEditor并覆盖该NewItemTypes属性- 并将此编辑器与您的类型相关联。我有点不清楚您想要添加哪些对象,以及这是否是最好的设计。如果你想添加现有的对象,你可能需要一个完全自定义的编辑器/uitypeeditor。


有了更新的问题,这听起来绝对像是一个定制的工作UITypeEditor;这是一个使用下拉菜单的版本;你也可以做弹出窗口(见方法svc):

using System.Collections.Generic;
using System.ComponentModel;
using System.Drawing.Design;
using System.Windows.Forms;
using System.Windows.Forms.Design;
using System.Collections;

static class Program
{
    static void Main()
    {
        MyWrapper wrapper = new MyWrapper();
        wrapper.Modules.Add(new ModuleData { ModuleId = 123 });
        wrapper.Modules.Add(new ModuleData { ModuleId = 456 });
        wrapper.Modules.Add(new ModuleData { ModuleId = 789 });

        wrapper.Batches.Add(new BatchData(wrapper) { BatchId = 666 });
        wrapper.Batches.Add(new BatchData(wrapper) { BatchId = 777 });

        PropertyGrid props = new PropertyGrid { Dock = DockStyle.Fill };
        ListView view = new ListView { Dock = DockStyle.Left };
        foreach (ModuleData mod in wrapper.Modules) {
            view.Items.Add(mod.ToString()).Tag = mod;
        }
        foreach (BatchData bat in wrapper.Batches) {
            view.Items.Add(bat.ToString()).Tag = bat;
        }
        view.SelectedIndexChanged += delegate {
            var sel = view.SelectedIndices;
            if(sel.Count > 0) {
                props.SelectedObject = view.Items[sel[0]].Tag;
            }
        };

        Application.Run(new Form { Controls = { props, view} });
    }
}

class MyWrapper
{
    private List<ModuleData> modules = new List<ModuleData>();
    public List<ModuleData> Modules { get { return modules; } }

    private List<BatchData> batches = new List<BatchData>();
    public List<BatchData> Batches { get { return batches; } }
}

class ModuleListEditor : UITypeEditor
{
    public override UITypeEditorEditStyle GetEditStyle(ITypeDescriptorContext context)
    {
         return UITypeEditorEditStyle.DropDown;
    }
    public override object  EditValue(ITypeDescriptorContext context, System.IServiceProvider provider, object value)
    {
        IWindowsFormsEditorService svc;
        IHasModules mods;
        IList selectedModules;
        if (context == null || (selectedModules = (IList)value) == null ||
            (mods = context.Instance as IHasModules) == null
            || (svc = (IWindowsFormsEditorService)
            provider.GetService(typeof(IWindowsFormsEditorService))) == null)
        {
            return value;
        }
        var available = mods.GetAvailableModules();
        CheckedListBox chk = new CheckedListBox();
        foreach(object item in available) {
            bool selected = selectedModules.Contains(item);
            chk.Items.Add(item, selected);
        }
        chk.ItemCheck += (s, a) =>
        {
            switch(a.NewValue) {
                case CheckState.Checked:
                    selectedModules.Add(chk.Items[a.Index]);
                    break;
                case CheckState.Unchecked:
                    selectedModules.Remove(chk.Items[a.Index]);
                    break;
            }
        };


        svc.DropDownControl(chk);

        return value;
    }
    public override bool IsDropDownResizable {
        get {
            return true;
        }
    }
}


interface IHasModules
{
    ModuleData[] GetAvailableModules();
}

internal class BatchData : IHasModules {
    private MyWrapper wrapper;
    public BatchData(MyWrapper wrapper) {
        this.wrapper = wrapper;
    }
    ModuleData[] IHasModules.GetAvailableModules() { return wrapper.Modules.ToArray(); }
    [DisplayName("Batch ID")]
    public int BatchId { get; set; }
    private List<ModuleData> modules = new List<ModuleData>();
    [Editor(typeof(ModuleListEditor), typeof(UITypeEditor))]
    public List<ModuleData> Modules { get { return modules; } set { modules = value; } }

    public override string ToString() {
        return "Batch " + BatchId;
    }
}

internal class ModuleData {
    [DisplayName("Module ID")]
    public int ModuleId { get; set; }

    public override string ToString() {
        return "Module " + ModuleId;
    }
}
于 2010-02-07T08:45:51.320 回答