将int list作为参数传递给Web用户控件

时间:2008-10-30 19:32:14

标签: c# asp.net typeconverter

我想将一个int列表(List)作为声明属性传递给Web用户控件,如下所示:

<UC:MyControl runat="server" ModuleIds="1,2,3" />

我创建了一个TypeConverter来执行此操作:

public class IntListConverter : System.ComponentModel.TypeConverter
{
    public override bool CanConvertFrom(
           System.ComponentModel.ITypeDescriptorContext context, 
           Type sourceType)
    {
        if (sourceType == typeof(string)) return true;
        return base.CanConvertFrom(context, sourceType);
    }
    public override object ConvertFrom(
      System.ComponentModel.ITypeDescriptorContext context, 
      System.Globalization.CultureInfo culture, object value)
    {
        if (value is string)
        {
            string[] v = ((string)value).Split(
                new char[] { ',' }, StringSplitOptions.RemoveEmptyEntries);
            List<int> list = new List<int>();
            foreach (string s in vals)
            {
                list.Add(Convert.ToInt32(s));
            }
            return list
        }
        return base.ConvertFrom(context, culture, value);
    }
    public override bool CanConvertTo(ITypeDescriptorContext context,
      Type destinationType)
    {
        if (destinationType == typeof(InstanceDescriptor)) return true;
        return base.CanConvertTo(context, destinationType);
    }
    public override object ConvertTo(ITypeDescriptorContext context,
      System.Globalization.CultureInfo culture, object value, Type destinationType)
    {
        if (destinationType == typeof(InstanceDescriptor) && value is List<int>)
        {
            List<int> list = (List<int>)value;
            ConstructorInfo construcor = typeof(List<int>).GetConstructor(new Type[] { typeof(IEnumerable<int>) });
            InstanceDescriptor id = new InstanceDescriptor(construcor, new object[] { list.ToArray() });
            return id;
        }
        return base.ConvertTo(context, culture, value, destinationType);
    }
}

然后将属性添加到我的属性中:

[TypeConverter(typeof(IntListConverter))]
public List<int> ModuleIds
{
    get { ... }; set { ... };
}

但是我在运行时遇到了这个错误:

Unable to generate code for a value of type 'System.Collections.Generic.List'1[[System.Int32, mscorlib, Version=2.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089]]'. This error occurred while trying to generate the property value for ModuleIds.

我的问题类似于here找到的问题,但解决方案无法解决我的问题:

更新:我找到了解决第一个问题的页面。我更新了上面的代码以显示我的修复程序。添加的代码是CanConvertToConvertTo方法。现在我得到了一个不同的错误。:

Object reference not set to an instance of an object.

此错误似乎是由ConvertTo方法中的某些内容间接引起的。

8 个答案:

答案 0 :(得分:10)

在将调试器挂钩到Cassini之后,我看到null ref实际上来自System.Web.Compilation.CodeDomUtility.GenerateExpressionForValue,它基本上试图获取传递给List构造函数的int []数组的表达式。因为int []数组没有类型描述符,所以它失败了(并且在进程中抛出了一个空引用,而不是“它不应该生成属性集异常”)。

我无法找到一种内置的方法来获取List&lt; int&gt;中的可序列化值,所以我只使用了静态方法:

class IntListConverter : TypeConverter {
    public static List<int> FromString(string value) {
       return new List<int>(
          value
           .Split(new char[] { ',' }, StringSplitOptions.RemoveEmptyEntries)
           .Select(s => Convert.ToInt32(s))
       );
    }

    public override object ConvertTo(ITypeDescriptorContext context, CultureInfo culture, object value, Type destinationType) {
        if (destinationType == typeof(InstanceDescriptor)) {
            List<int> list = (List<int>)value;
            return new InstanceDescriptor(this.GetType().GetMethod("FromString"),
                new object[] { string.Join(",", list.Select(i => i.ToString()).ToArray()) }
            );
        }
        return base.ConvertTo(context, culture, value, destinationType);
    }
}

答案 1 :(得分:1)

虽然我不能说我对此错误有任何特殊经验,但其他来源表明您需要向InstanceDescriptor类型添加转换。退房:

http://weblogs.asp.net/bleroy/archive/2005/04/28/405013.aspx

其中提供了原因的解释或者:

http://forums.asp.net/p/1191839/2052438.aspx#2052438

提供与您类似的示例代码。

答案 2 :(得分:1)

我通过创建2个属性解决了类似问题:

public List<int> ModuleIDs { get .... set ... }
public string ModuleIDstring { get ... set ... }

ModuleIDstring将其值集转换为列表并设置ModuleIDs属性。

这也将使ModuleID可以从PropertyGrid等中使用。

好吧,不是最好的,类型安全的解决方案,但对我来说它有效。

答案 3 :(得分:0)

从后面的代码传递列表......

ASPX:

<UC:MyControl id="uc" runat="server" />

代码隐藏:

List<int> list = new List<int>();
list.add(1);
list.add(2);
list.add(3);

uc.ModuleIds = list;

答案 4 :(得分:0)

我通常这样做的方法是使属性包装ViewState集合。如果它可以使你的方式更好看,但这将完成工作:

public IList<int> ModuleIds
{
   get
   {
       string moduleIds = Convert.ToString(ViewState["ModuleIds"])

       IList<int> list = new Collection<int>();

       foreach(string moduleId in moduleIds.split(","))
       {
          list.Add(Convert.ToInt32(moduleId));
       }

      return list;
   }
}

答案 5 :(得分:0)

我认为问题是集{}。类型转换器希望将List<int>更改回字符串,但CanConvertFrom()的{​​{1}}失败。

答案 6 :(得分:0)

您可以将其传递给字符串并在逗号上拆分以填充私有变量。没有归属的精确性,但会起作用。

private List<int> modules;
public string ModuleIds
{
  set{
    if (!string.IsNullOrEmpty(value))
    {
    if (modules == null) modules = new List<int>();
    var ids = value.Split(new []{','});
    if (ids.Length>0)
      foreach (var id in ids)
        modules.Add((int.Parse(id)));
    }
}

答案 7 :(得分:0)

我认为您最好的选择是让您的usercontrol具有DataSource样式的属性。

将属性作为对象,然后对IList / IEnumerable / etc进行一些类型检查,以确保它是正确的。