c# - PropertyGrid - 根据另一个属性值更改下拉属性编辑器的项目

标签 c# .net winforms custom-component propertygrid

我正在尝试在自定义组件中实现下拉属性,并且我使用了 This SO Answerthis answer作为指导。

到目前为止,我设法让它工作,并在下拉列表中使用预定义的项目。
但我仍然需要弄清楚如何更改下拉列表中的项目?

这是我到目前为止的代码(从上面提到的链接构建)

[TypeConverter(typeof(TableNameConverter))]
public TableName gttTableName
{ get; set; }

...

public class TableName
{
    public string Name { get; set; }

    public override string ToString()
    {
        return $"{Name}";
    }
}

public class TableNameService
{
    List<TableName> list = new List<TableName>() {
        new TableName() {Name = "naam 1" },
        new TableName() {Name = "naam 2" },
    };

    public IEnumerable<TableName> GetAll()
    {
        return list;
    }
}

public class TableNameConverter : TypeConverter
{
    public override StandardValuesCollection GetStandardValues(ITypeDescriptorContext context)
    {
        var svc = new TableNameService();
        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 name = v.ToString();
            var svc = new TableNameService();
            //return svc.GetAll().Where(x => x.Id == id).FirstOrDefault();
            return svc.GetAll().Where(x => x.Name == name).FirstOrDefault();
        }
        return base.ConvertFrom(context, culture, value);
    }
}

这在 VS 属性窗口中看起来像这样

enter image description here

现在的问题是,当某个属性发生变化时,下拉属性中的项目也必须发生变化。这应该在方法 UpdateTableNames 中完成(代码如下)。
换句话说,在另一个属性的 setter 中,项目 naam 1naam 2 可以更改为一个完整的新集合,具有更多或更少的项目以及不同的值。< br/> 我还不知道如何更改这些项目?

让我解释一下情况。

  • 用户将自定义组件拖放到表单上
  • 当他查看属性 gttTableName 时,它​​现在会显示 naam 1naam 2
  • 现在,用户更改另一个属性 (gttDataModule),并且在该属性的 setter 中,gttTableName 属性的项目可以更改。
  • 因此,如果他再次查看属性 gttTableName,它现在应该显示完整的其他值列表。

属性 gttDataModule 的代码是这样的

public gttDataModule gttDataModule
{
    get { return _gttDataModule; }
    set
    {
        _gttDataModule = value;
        UpdateTableNames();
    }
}

private void UpdateTableNames()
{
    List<string> tableNames = new List<string>();
    if (_gttDataModule != null)
    {
        foreach (gttDataTable table in _gttDataModule.gttDataTables)
        {
            tableNames.Add(table.Table.TableName);
        }
    }

    // at this point the list tableNames will be populated with values.
    // What I need is to replace the list in TableNameService from 'naam 1', 'naam 2' 
    // to the values in this list.
    // so they won't be 'naam 1' and 'naam 2' anymore 
    // It could be more or less items or even none 
    // They could have different values
    // for example the list could be 'tblBox', 'tblUser', tblClient', tblOrders'
    // or it could be empty
    // or it could be 'vwCars', 'tblSettings'
}

如何更改 TableNameServicelist 中的项目?

最佳答案

我将根据这篇文章中的答案创建一个示例:PropertyGrid - Load dropdown values dynamically .

基本思想是拥有自定义类型转换器并覆盖 GetStandardValues返回编辑属性支持的值列表。

这里的重点是使用 context.Instance获取正在编辑的对象的实例,并尝试根据编辑对象的其他属性过滤列表。

在下面的示例中,我将编辑一个 Product,它具有 CategorySubCategory 属性,并且类别和类别之间存在关系子类别。例如,如果您选择类别 1,则子类别列表应显示类别 1 的子类别,但如果您选择类别 2,则列表应显示另一组子类别,如下所示:

enter image description here

这是示例的代码:

using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Globalization;
using System.Linq;
public class Product
{
    public int Id { get; set; }
    public string Name { get; set; }
    private Category category;
    [TypeConverter(typeof(CategoryConverter))]
    public Category Category
    {
        get { return category; }
        set
        {
            if (category?.Id != value?.Id)
            {
                category = value;
                SubCategory = null;
            }
        }
    }
    [TypeConverter(typeof(SubCategoryConverter))]
    public SubCategory SubCategory { get; set; }
}
public class Category
{
    public int Id { get; set; }
    public string Name { get; set; }
    public override string ToString()
    {
        return $"{Id} - {Name}";
    }
}
public class SubCategory
{
    public int Id { get; set; }
    public int CategoryId { get; set; }
    public string Name { get; set; }
    public override string ToString()
    {
        return $"{Id} - {Name}";
    }
}
public class CategoryService
{
    List<Category> categories = new List<Category> {
        new Category() { Id = 1, Name = "Category 1" },
        new Category() { Id = 2, Name = "Category 2" },
    };
    List<SubCategory> subCategories = new List<SubCategory> {
        new SubCategory() { Id = 11, Name = "Sub Category 1-1", CategoryId= 1 },
        new SubCategory() { Id = 12, Name = "Sub Category 1-2", CategoryId= 1 },
        new SubCategory() { Id = 13, Name = "Sub Category 1-3", CategoryId= 1 },
        new SubCategory() { Id = 21, Name = "Sub Category 2-1", CategoryId= 2 },
        new SubCategory() { Id = 22, Name = "Sub Category 2-2", CategoryId= 2 },
    };
    public IEnumerable<Category> GetCategories()
    {
        return categories;
    }
    public IEnumerable<SubCategory> GetSubCategories()
    {
        return subCategories.ToList();
    }
}
public class CategoryConverter : TypeConverter
{
    public override StandardValuesCollection GetStandardValues(
        ITypeDescriptorContext context)
    {
        var svc = new CategoryService();
        return new StandardValuesCollection(svc.GetCategories().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.GetCategories()
                .Where(x => x.Id == id).FirstOrDefault();
        }
        return base.ConvertFrom(context, culture, value);
    }
}
public class SubCategoryConverter : TypeConverter
{
    public override StandardValuesCollection GetStandardValues(
        ITypeDescriptorContext context)
    {
        var svc = new CategoryService();
        var categoryId = ((Product)context.Instance).Category.Id;
        return new StandardValuesCollection(svc.GetSubCategories()
            .Where(x => x.CategoryId == categoryId).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.GetSubCategories()
                .Where(x => x.Id == id).FirstOrDefault();
        }
        return base.ConvertFrom(context, culture, value);
    }
}

关于c# - PropertyGrid - 根据另一个属性值更改下拉属性编辑器的项目,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/65842530/

相关文章:

string - 删除字符串的内容 - TextBox 的行为与 DataGridView 文本单元格略有不同

c# - 开源 Winforms 应用程序?

c# - 如何让 VS 不复制我的 C# 文件

.net - 类库中的 WebBrowser 控件

Jquery DataTable fnServerData 错误

c# - 最小起订量错误 : Cannot cast 'AnObject' to 'System.Delegate'

c# - 从 .txt 文件读取时如何指示空格

c# - 如何从应用程序级别使用 Azure 中的服务配置?

c# - 我是否在我的一个页面中滥用了 WebMatrix 的 AntiForgery.Validate 助手?

javascript - 从 JavaScript 运行 WScript.Shell.Run() 时获取 "Wrong number of arguments or invalid property assignment"