Поле со списком данных в PropertyGrid
Я пробовал все виды - много возился с TypeConverters и т. Д. Так что я не буду все это освещать здесь.
Итак, чтобы свести вопрос к его основам. Учитывая следующее:
Imports LiteDB
Imports System.ComponentModel
Public Class mSystem
<CategoryAttribute("General"), ReadOnlyAttribute(True)>
Public Property ID As Integer
Public Property ShortName As String = ""
<BsonRef("mSystemTypes")>
Public Property SystemType As mSystemType
End Class
Public Class mSystemType
<CategoryAttribute("General"), ReadOnlyAttribute(True)>
Public Property ID As Integer
Public Property Name As String = "Default"
Public Property Details As String = ""
End Class
Как получить "SystemTypes" в качестве выпадающего селектора, динамически заполняемого из коллекции mSystemTypes? Например, вы выбираете "Консоль", и она обновляет mSystem с соответствующим mSystemType.
Я использую LiteDb, что может немного усложнить задачу, поскольку это не просто целое число для "внешнего ключа", как могут представлять другие сценарии, а полный объект.
Мне нужно поддерживать подход "dbRef" для обеспечения целостности отношений данных. На всякий случай, если вещь DBLite добавляет изогнутый шар, ниже приведен код, демонстрирующий ее использование:
Public Class dbCollecitons
Public mSystems As LiteCollection(Of mSystem)
Public mSystemTypes As LiteCollection(Of mSystemType)
Private Sub Examples()
Dim col As LiteCollection(Of mSystemType) = dbCollections.mSystemTypes
Dim value as String = "Console"
Dim q = col.FindAll.Where(Function(x) x.Name = value).First
Console.Writeline(q.ID)
End Sub
End Class
LiteDb.LiteCollection не отображается непосредственно на ICollection (вы используете это в TypeConverter?), Но я уверен, что есть некоторые обходные пути.
0 ответов
Короче нужно создать новый TypeConverter
поддерживая стандартные значения.
Пример - VB.NET
Я полагаю, у вас есть Product
класс, имеющий свойство типа Category
который вы хотите иметь возможность выбрать из List<Category>
который приходит откуда-то вроде базы данных во время выполнения:
Public Class Product
Public Property Id As Integer
Public Property Name As String
<TypeConverter(GetType(CategoryConverter))>
Public Property Category As Category
End Class
Public Class Category
Public Property Id As Integer
Public Property Name As String
Public Overrides Function ToString() As String
Return $"{Id} - {Name}"
End Function
End Class
А вот и CategoryService
класс, который может загружать категории из любого места:
Public Class CategoryService
Private list As List(Of Category) = New List(Of Category) From {
New Category() With {.Id = 1, .Name = "Category 1"},
New Category() With {.Id = 2, .Name = "Category 2"},
New Category() With {.Id = 3, .Name = "Category 3"}
}
Public Function GetAll() As IEnumerable(Of Category)
Return list
End Function
End Class
Следующим шагом является создание CategoryConverter
который отвечает за предоставление значений для раскрывающегося списка:
Imports System.ComponentModel
Public Class CategoryConverter
Inherits TypeConverter
Public Overrides Function GetStandardValues(ByVal context As ITypeDescriptorContext) As StandardValuesCollection
Dim svc = New CategoryService()
Return New StandardValuesCollection(svc.GetAll().ToList())
End Function
Public Overrides Function GetStandardValuesSupported(ByVal context As ITypeDescriptorContext) As Boolean
Return True
End Function
Public Overrides Function GetStandardValuesExclusive(ByVal context As ITypeDescriptorContext) As Boolean
Return True
End Function
Public Overrides Function CanConvertFrom(ByVal context As ITypeDescriptorContext, ByVal sourceType As Type) As Boolean
If sourceType = GetType(String) Then Return True
Return MyBase.CanConvertFrom(context, sourceType)
End Function
Public Overrides Function ConvertFrom(context As ITypeDescriptorContext, culture As CultureInfo, value As Object) As Object
If value IsNot Nothing AndAlso value.[GetType]() = GetType(String) Then
Dim v = $"{value}"
Dim id = Integer.Parse(v.Split("-"c)(0).Trim())
Dim svc = New CategoryService()
Return svc.GetAll().Where(Function(x) x.Id = id).FirstOrDefault()
End If
Return MyBase.ConvertFrom(context, culture, value)
End Function
End Class
Затем в результате, когда вы устанавливаете экземпляр Product
как SelectedObject
из PropertyGrid
, за Category
свойство, вы выбираете значение из списка.
Пример - C#
Вот версия C# приведенного выше примера:
public class Product
{
public int Id { get; set; }
public string Name { get; set; }
[TypeConverter(typeof(CategoryConverter))]
public Category Category { get; set; }
}
public class Category
{
public int Id { get; set; }
public string Name { get; set; }
public override string ToString()
{
return $"{Id} - {Name}";
}
}
public class CategoryService
{
List<Category> list = new List<Category>{
new Category() { Id = 1, Name = "Category 1" },
new Category() { Id = 2, Name = "Category 2" },
new Category() { Id = 3, Name = "Category 3" },
};
public IEnumerable<Category> GetAll()
{
return list;
}
}
public class CategoryConverter : TypeConverter
{
public override StandardValuesCollection GetStandardValues(ITypeDescriptorContext context)
{
var svc = new CategoryService();
return new StandardValuesCollection(svc.GetAll().ToList());
}
public override bool GetStandardValuesSupported(ITypeDescriptorContext context)
{
return true;
}
public override bool GetStandardValuesExclusive(ITypeDescriptorContext context)
{
return true;
}
public override bool CanConvertFrom(ITypeDescriptorContext context, Type sourceType)
{
if (sourceType == typeof(string))
return true;
return base.CanConvertFrom(context, sourceType);
}
public override object ConvertFrom(ITypeDescriptorContext context, CultureInfo culture, object value)
{
if (value != null && value.GetType() == typeof(string))
{
var v = $"{value}";
var id = int.Parse(v.Split('-')[0].Trim());
var svc = new CategoryService();
return svc.GetAll().Where(x => x.Id == id).FirstOrDefault();
}
return base.ConvertFrom(context, culture, value);
}
}