简体   繁体   English

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

[英]Passing int list as a parameter to a web user control

I want to pass an int list (List) as a declarative property to a web user control like this: 我想将一个int列表(List)作为声明属性传递给Web用户控件,如下所示:

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

I created a TypeConverter to do this: 我创建了一个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);
    }
}

And then added the attribute to my property: 然后将属性添加到我的属性:

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

But I get this error at runtime: 但是我在运行时遇到这个错误:

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.

My question is similar to one found here , but the solution does not solve my problem: 我的问题类似于这里发现的问题 ,但解决方案并没有解决我的问题:

Update: I found a page which solved the first problem. 更新:我找到了解决第一个问题的页面。 I updated the code above to show my fixes. 我更新了上面的代码以显示我的修复程序。 The added code is the CanConvertTo and ConvertTo methods. 添加的代码是CanConvertToConvertTo方法。 Now I get a different error.: 现在我得到一个不同的错误:

Object reference not set to an instance of an object.

This error seems to be indirectly caused by something in the ConvertTo method. 这个错误似乎是由ConvertTo方法中的某些东西间接引起的。

After hooking a debugger into Cassini, I see that the null ref is actually coming from System.Web.Compilation.CodeDomUtility.GenerateExpressionForValue, which is basically trying to get an expression for the int[] array you pass into the List constructor. 在将调试器挂钩到Cassini之后,我发现null ref实际上来自System.Web.Compilation.CodeDomUtility.GenerateExpressionForValue,它基本上试图获取传递给List构造函数的int []数组的表达式。 Since there's no type descriptor for the int[] array, it fails (and throws a null ref in the process, instead of the "can't generate property set exception" that it should). 由于int []数组没有类型描述符,它会失败(并在进程中抛出一个空引用,而不是它应该生成的“无法生成属性集异常”)。

I can't figure out a built in way of getting a serializable value into a List<int>, so I just used a static method: 我无法想出一个内置的方法来获取List <int>中的可序列化值,所以我只使用了一个静态方法:

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

WHile I can't say I have any particular experience with this error, other sources indicate that you need to add a conversion to the type InstanceDescriptor. 虽然我不能说我对此错误有任何特殊经验,但其他来源表明您需要向InstanceDescriptor类型添加转换。 check out: 查看:

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

Which provides an explanation of the reasons or alternatively: 其中提供了原因的解释或者:

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

Which provides example code similar to yours. 其中提供了类似于您的示例代码。

I solved something simular by creating 2 properties: 我通过创建2个属性解决了类似的问题:

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

The ModuleIDstring converts its value set to a list and sets the ModuleIDs property. ModuleIDstring将其值集转换为列表并设置ModuleIDs属性。

This will also make the ModuleIDs usable from a PropertyGrid etc. 这也将使ModuleID可用于PropertyGrid等。

Ok, not the best, typesafe solution, but for me it works. 好吧,不是最好的,类型安全的解决方案,但对我来说它是有效的。

pass the list from the code behind... 从后面的代码传递列表...

aspx: ASPX:

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

code-behind: 后台代码:

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

uc.ModuleIds = list;

The way I normally do this is to make the property wrap the ViewState collection. 我通常这样做的方法是使属性包装ViewState集合。 Your way looks better if it can be made to work, but this will get the job done: 如果它可以工作,你的方式看起来会更好,但这将完成工作:

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

I believe the problem is the set{}. 我相信问题是集{}。 The type converter want to change the List<int> back into a string, but CanConvertFrom() fails for List<int> . 类型转换器想要将List<int>更改回字符串,但是List<int> CanConvertFrom()失败。

You can pass it into a string and split on comma to populate a private variable. 您可以将其传递给字符串并在逗号上拆分以填充私有变量。 Does not have the nicety of attribution, but will work. 没有归属的精确性,但会起作用。

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

I think that you're best option is to make your usercontrol have a DataSource-style property. 我认为您最好的选择是让您的usercontrol具有DataSource样式的属性。

You take the property as an object and then do some type checking against IList/ IEnumerable/ etc to make sure that it is correct. 您将该属性作为对象,然后对IList / IEnumerable / etc进行一些类型检查以确保它是正确的。

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM