c# - PropertyGrid - 动态加载下拉值

标签 c# .net vb.net winforms propertygrid

我已经尝试了各种方法 - 很多乱七八糟的类型转换器等。所以我不会在这里介绍所有这些。

因此,将问题简化为最基本的问题。考虑以下因素:

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

如何从 mSystemTypes 集合中动态填充“SystemTypes”作为下拉选择器?例如。您选择“Console”,它会使用匹配的 mSystemType 更新 mSystem。

我正在使用 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 中使用它吗?),但我确信有一些解决方法。

最佳答案

简而言之,您需要创建一个新的 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);
    }
}

关于c# - PropertyGrid - 动态加载下拉值,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/53566675/

相关文章:

c# - 在 Winform 中的 datagridview 底部添加新行

.net - 何时使用 Entity Framework 预生成 View

vb.net - 如何在 PictureBox 控件上显示滚动条?

.net - DataTable 已属于另一个 DataSet

c# - 为什么点击ToolStripMenuItem需要两次点击?

c# - 如何仅在应用程序打开并运行时在后台运行方法?

c++ - 字符串替换成几种组合

c# - 使用 MySQL AES_ENCRYPT/AES_DECRYPT 移动代码以避免 SQL 注入(inject)

c# - NHibernate IPreUpdateEventListener,IPreInsertEventListener 不保存到数据库

c# - 为什么我的属性(property)不知道直接对数据库所做的更改