如何将 PropertyGrid 集合限制为 List

发布于 2024-08-20 22:11:11 字数 1178 浏览 6 评论 0原文

好的,我已经阅读了几个有关 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 对象添加到 BatchData Module 集合中。 ListView 控件中列出了符合添加条件的 ModuleData 对象。

编辑:删除了 : List 继承。

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

Okay, I've read a couple of questions regarding the use of the PropertyGrid and collections. But, I'm having a difficult time understanding how/if [TypeConverter] will work for me. I've read the little blurb-age that MSDN puts out there, and frankly, it's a bit lacking to this poor, self-taught programmer.

So, here is what I have. First a collection:

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

private List<ModuleData> modules;

The object in the collection:

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

I have a ListView control that contains items describing both ModuleData objects and BatchData objects. When I select a BatchData item from the ListView, the PropertyGrid, as expected, displays the collection editor. Is there a way to limit the collection editor to any ModuleData items listed in the ListView control only? Ideally I would not want a BatchData item (from the ListView) to be added to a BatchData collection - especially since the collection is not 'typed' for BatchData object types.

If any further code samples are requested, I'll be more than happy to edit some snippets in.

For clarity, ModuleData is a custom class that holds data required to instance a class within a specified assembly. All it contains are fields and public/internal properties. What I would like to do is use the collection editor assembled with the property grid control to add ModuleData objects to the BatchData Module collection. The ModuleData objects that are qualified to be added are listed in the ListView control.

EDIT: Removed the : List<ModuleData> inheritance.

UPDATE: If I am going to create a custom collection editor, does that mean I am building my own custom form/dialog? Then basically providing the propertygrid the information to display my custom collection dialog through attributes and inheritance of an UITypeEditor?

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(1

彩扇题诗 2024-08-27 22:11:11

首先,我有点不确定为什么这两个继承 (: List) 和包装 (public ListModules { 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;
    }
}

First off I'm a little unsure about why this both inherits (: List<ModuleData>) and wraps (public List<ModuleData> Modules { get { return this; } }) a list - either individually should be fine.

However! To define the types of new objects you can create you need to derive from CollectionEditor and override the NewItemTypes property - and associate this editor with your type. I'm a little bit unclear on what objects you want to be addable, and whether this is the best design. If you want to add existing objects you may need a completely custom editor / uitypeeditor.


With the updated question, it definitely sounds like a job for a custom UITypeEditor; here's a version that uses a drop-down; you can do popups too (see methods on 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;
    }
}
~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文