更改基于另一个属性的下拉属性编辑器的项目? [英] Change items of a dropdown property editor based on another property?

查看:57
本文介绍了更改基于另一个属性的下拉属性编辑器的项目?的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我正在尝试在自定义组件中实现下拉属性,并且我使用了

现在解决此问题,当某个属性更改时,下拉属性中的项必须更改.这应该在方法 UpdateTableNames (代码在下面)中完成.
换句话说,在另一个属性的设置器中,项目 naam 1 naam 2 可以更改为一个完整的新集合,其中包含或多或少的项目,并且值不同.
我还不知道如何更改这些项目?

让我解释一下情况.

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

属性gttDataModule的代码是这样

 公共gttDataModule gttDataModule{得到{return _gttDataModule;}放{_gttDataModule =值;UpdateTableNames();}}私有无效UpdateTableNames(){List< string>tableNames = new List< string>();如果(_gttDataModule!= null){foreach(_gttDataModule.gttDataTables中的gttDataTable表){tableNames.Add(table.Table.TableName);}}//此时,列表tableNames将填充值.//我需要从'naam 1','naam 2'替换TableNameService中的列表//到此列表中的值.//因此它们将不再是"naam 1"和"naam 2"//它可能是或多或少的项目,甚至没有//它们可以具有不同的值//例如,列表可以是'tblBox','tblUser',tblClient',tblOrders'//否则可能为空//或者可以是'vwCars','tblSettings'} 

如何更改 TableNameService 列表中的项目?

解决方案

我将根据本文中的答案创建一个示例:

这是示例代码:

 使用系统;使用System.Collections.Generic;使用System.ComponentModel;使用System.Globalization;使用System.Linq;公共类产品{public int ID {get;放;}公共字符串名称{get;放;}私人类别类别;[TypeConverter(typeof(CategoryConverter))]公共类别类别{得到{返回类别;}放{if(类别?.Id!=值?.Id){类别=值;SubCategory = null;}}}[TypeConverter(typeof(SubCategoryConverter))]公共SubCategory SubCategory {get;放;}}公共类类别{public int ID {get;放;}公共字符串名称{get;放;}公共重写字符串ToString(){返回$" {Id}-{Name}" ;;}}公共类SubCategory{public int ID {get;放;}public int CategoryId {获取;放;}公共字符串名称{get;放;}公共重写字符串ToString(){返回$" {Id}-{Name}" ;;}}公共类CategoryService{列表<类别>类别=新的List< Category>{new Category(){ID = 1,名称=类别1";},new Category(){ID = 2,Name =类别2";},};列表< SubCategory>subCategories = new List< SubCategory>{new SubCategory(){ID = 11,名称=子类别1-1",CategoryId = 1},new SubCategory(){ID = 12,名称=子类别1-2",CategoryId = 1},new SubCategory(){ID = 13,名称=子类别1-3",CategoryId = 1},new SubCategory(){ID = 21,名称=子类别2-1",CategoryId = 2},new SubCategory(){ID = 22,名称=子类别2-2",CategoryId = 2},};公共IEnumerable< Category>GetCategories(){返回类别;}公共IEnumerable< SubCategory>GetSubCategories(){返回subCategories.ToList();}}公共类CategoryConverter:TypeConverter{公共重写StandardValuesCollection GetStandardValues(ITypeDescriptorContext上下文){var svc = new CategoryService();返回新的StandardValuesCollection(svc.GetCategories().ToList());}公共重写布尔GetStandardValuesSupported(ITypeDescriptorContext上下文){返回true;}公共重写布尔GetStandardValuesExclusive(ITypeDescriptorContext上下文){返回true;}公共重写bool CanConvertFrom(ITypeDescriptorContext上下文,输入sourceType){如果(sourceType == typeof(string))返回true;返回base.CanConvertFrom(context,sourceType);}公共重写对象ConvertFrom(ITypeDescriptorContext上下文,CultureInfo文化,对象值){if(值!=空&& value.GetType()== typeof(字符串)){var v = $"{value}";var id = int.Parse(v.Split('-')[0] .Trim());var svc = new CategoryService();返回svc.GetCategories().Where(x => x.Id == id).FirstOrDefault();}返回base.ConvertFrom(上下文,文化,价值);}}公共类SubCategoryConverter:TypeConverter{公共重写StandardValuesCollection GetStandardValues(ITypeDescriptorContext上下文){var svc = new CategoryService();var categoryId =(((Product)context.Instance).Category.Id;返回新的StandardValuesCollection(svc.GetSubCategories().where(x => x.CategoryId == categoryId).ToList());}公共重写布尔GetStandardValuesSupported(ITypeDescriptorContext上下文){返回true;}公共重写布尔GetStandardValuesExclusive(ITypeDescriptorContext上下文){返回true;}公共重写bool CanConvertFrom(ITypeDescriptorContext上下文,输入sourceType){如果(sourceType == typeof(string))返回true;返回base.CanConvertFrom(context,sourceType);}公共重写对象ConvertFrom(ITypeDescriptorContext上下文,CultureInfo文化,对象值){if(值!=空&& value.GetType()== typeof(字符串)){var v = $"{value}";var id = int.Parse(v.Split('-')[0] .Trim());var svc = new CategoryService();返回svc.GetSubCategories().Where(x => x.Id == id).FirstOrDefault();}返回base.ConvertFrom(上下文,文化,价值);}} 

I am trying to implement a drop-down property in a custom component, and I used This SO Answer and this answer as a guide.

So far I managed to get it working, with predefined items in the drop-down list.
But I still need to figure out how to alter the items in the drop-down list ?

This is the code I have so far (build from the link mentioned above)

[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);
    }
}

This looks like this in VS property window

Now for the problem, when a certain property changes then the items in the drop-down property must change. This should be done in the method UpdateTableNames(code is below).
In other words, in the setter of another property the items naam 1, naam 2 can change to a complete new set, with more or less items and with different values.
What I can not figure out yet is how can I alter these items ?

Let me explain the situation.

  • A user drops the custom component on a form
  • when he looks at the property gttTableName it will now show naam 1 and naam 2
  • Now the user changes another property (gttDataModule) and in the setter of this property the items of the gttTableName property can change.
  • So if he looks again at the property gttTableName it should now show a complete other list of values.

The code for the property gttDataModule is this

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'
}

How can I change the items in the list of the TableNameService ?

解决方案

I would create an example based on the answer in this post: PropertyGrid - Load dropdown values dynamically.

The basic idea is having custom type converter and overriding GetStandardValues to return a list of supported values for the editing property.

The point here is using the context.Instance to get an instance of the object which is editing and trying to filter the list based on the other properties of the editing object.

In the following example, I'll edit a Product which has a Category and a SubCategory property and there's a relation between categories and sub-categories. For example if you choose category 1, then the sub-categories list should show the sub-categories of category 1, but if you choose category 2, then the list should show a different group of sub categories, like this:

And this is the code for the example:

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);
    }
}

这篇关于更改基于另一个属性的下拉属性编辑器的项目?的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆