Как ограничить коллекцию PropertyGrid списком<T>
-
19-09-2019 - |
Вопрос
Хорошо, я прочитал пару вопросов, касающихся использования 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.Когда я выбираю элемент BatchData из ListView, PropertyGrid, как и ожидалось, отображает редактор коллекции.Есть ли способ ограничить редактор коллекций любыми элементами ModuleData, перечисленными только в элементе управления ListView?В идеале я бы не хотел, чтобы элемент BatchData (из ListView) добавлялся в коллекцию BatchData, тем более что коллекция не "типизирована" для типов объектов BatchData.
Если будут запрошены какие-либо дополнительные образцы кода, я буду более чем счастлив отредактировать некоторые фрагменты.
Для наглядности ModuleData - это пользовательский класс, который содержит данные, необходимые для создания экземпляра класса в указанной сборке.Все, что он содержит, - это поля и общедоступные / внутренние свойства.Что я хотел бы сделать, так это использовать редактор коллекций, собранный с помощью элемента управления property grid, для добавления объектов ModuleData в BatchData Module
Коллекция.Объекты ModuleData, которые могут быть добавлены, перечислены в элементе управления ListView.
Редактировать:Удалил : List<ModuleData>
наследование.
Обновить:Если я собираюсь создать пользовательский редактор коллекций, означает ли это, что я создаю свою собственную пользовательскую форму / диалоговое окно?Затем, в основном предоставляя propertygrid информацию для отображения моего пользовательского диалогового окна коллекции через атрибуты и наследование UITypeEditor?
Решение
Во-первых, я маленький не уверен в том, почему это оба наследует (: 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;
}
}