好的,我已经阅读了有关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
集合。有资格添加的ModuleData对象列在ListView控件中。
编辑:删除了: List<ModuleData>
继承。
更新:如果我要创建自定义集合编辑器,这是否意味着我正在构建自己的自定义表单/对话框?然后基本上为propertygrid提供信息,通过属性和UITypeEditor的继承来显示我的自定义集合对话框?
答案 0 :(得分:4)
首先,我是小不确定为什么这两个都继承(: List<ModuleData>
)和包裹(public List<ModuleData> Modules { get { return this; } }
)一个列表 - 要么单独应该没问题。
然而!要定义您可以创建的新对象的类型,您需要从CollectionEditor
派生并覆盖NewItemTypes
property - 并将此编辑器与您的类型相关联。我是 little 有点不清楚你想要添加什么对象,以及这是否是最好的设计。如果您想添加现有的对象,您可能需要一个完全自定义的编辑器/ 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;
}
}