c# - 如何将 PropertyGrid 集合限制为 List<T>

标签 c# propertygrid collectioneditor

好的,我已经阅读了几个有关 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 是一个自定义类,它保存在指定程序集中实例化类所需的数据。它包含的只是字段和公共(public)/内部属性。我想做的是使用与属性网格控件组装的集合编辑器将 ModuleData 对象添加到 BatchData Module收藏。 ListView控件中列出了符合添加条件的ModuleData对象。

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

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

最佳答案

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

但是!要定义您可以创建的新对象的类型,您需要从 CollectionEditor 派生并覆盖 NewItemTypes property - 并将此编辑器与您的类型相关联。我有点不清楚您想要添加哪些对象,以及这是否是最好的设计。如果您想添加现有对象,您可能需要一个完全自定义的编辑器/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;
    }
}

关于c# - 如何将 PropertyGrid 集合限制为 List<T>,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/2216209/

相关文章:

c# - Paypal REST API SDK - 在 C# 中激活计费计划

c# - 如何填充使用 PropertyGrid 的 CollectionEditor(扩展 WPF 工具包)时出现的 CollectionControlDialog?

c# - CollectionEditor 的父级

c# - 如何创建用于属性网格的自定义集合编辑器表单?

c# - Nito.AsyncEx.AsyncLock 堆栈溢出,带有大量等待者和同步快速路径

c# - 获取从 .msg 文件打开的 MailItem 的 RDOMail

c# - 在 C# 中打印 Form/UserControl

c# - 寻找一种在 PropertyGrid 中动态更改字段名称的方法

C#/winforms : how to best bind a propertygrid and a System. 数据.数据行

c# - 如何获取 PropertyGrid 的单元格值 (c#)?