【问题标题】:How to limit a PropertyGrid collection to a List<T>如何将 PropertyGrid 集合限制为 List<T>
【发布时间】:2011-01-14 01:04:34
【问题描述】:

好的,我已经阅读了一些关于使用 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 对象类型的“类型化”。

如果需要更多代码示例,我将非常乐意编辑一些 sn-ps。

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

编辑:删除了: List&lt;ModuleData&gt; 继承。

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

【问题讨论】:

  • 我已经尝试添加一些想法,但对于您想要发生的确切,我仍然很模糊。
  • @Marc - 已编辑,希望有所澄清。
  • @Marc - 为了完成我的任务,我想我必须改变这个问题,这不是犹太教(根据我在 meta 中读到的内容)。所以,我会接受你的回答——我不喜欢松散的结局。 ;) 它确实帮助我研究了不同的途径,所以这是一个可行的答案!
  • 耻辱,我一直在努力...查看更新。

标签: c# propertygrid collectioneditor


【解决方案1】:

首先,我有点不确定为什么这两者都继承 (: List&lt;ModuleData&gt;) 和包装 (public List&lt;ModuleData&gt; 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;
    }
}

【讨论】:

  • 我的整个评论都消失了。 :( 好的,再来一次...我有return this; 的属性,因为我在propgrid.SelectedObject = myBatchData 中看不到该集合。我会在明天睡一会后查看链接。谢谢!!!
  • @Marc:天啊...你确定你没有在写问题之前冒充 Jon Skeet 并写答案吗?大声笑......这回答了这个问题......那个......本来......
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 2013-11-07
  • 2023-04-09
  • 1970-01-01
  • 2016-09-28
  • 1970-01-01
  • 2010-12-05
  • 1970-01-01
相关资源
最近更新 更多