Pregunta

Quiero pasar una lista int (Lista) como propiedad declarativa a un control de usuario web como este:

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

Creé un TypeConverter para hacer esto:

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

Y luego agregué el atributo a mi propiedad:

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

Pero me sale este error en tiempo de ejecución:

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.

Mi pregunta es similar a una encontrada. aquí, pero la solución no resuelve mi problema:

Actualizar: Encontré una página que resolvió el primer problema.Actualicé el código anterior para mostrar mis correcciones.El código agregado es el CanConvertTo y ConvertTo métodos.Ahora me sale un error diferente:

Object reference not set to an instance of an object.

Este error parece ser causado indirectamente por algo en el ConvertTo método.

¿Fue útil?

Solución

Después de conectar un depurador a Cassini, veo que la referencia nula en realidad proviene de System.Web.Compilation.CodeDomUtility.GenerateExpressionForValue, que básicamente está tratando de obtener una expresión para la matriz int [] que pasa al constructor de listas . Como no hay un descriptor de tipo para la matriz int [], falla (y arroja una referencia nula en el proceso, en lugar de & Quot; no se puede generar la excepción de conjunto de propiedades & Quot; que debería).

No puedo encontrar una forma integrada de obtener un valor serializable en una Lista < int > ;, así que simplemente utilicé un método estático:

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

Otros consejos

MIENTRAS que no puedo decir que tenga una experiencia particular con este error, otras fuentes indican que necesita agregar una conversión al tipo InstanceDescriptor. echa un vistazo:

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

Que proporciona una explicación de los motivos o, alternativamente:

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

Que proporciona un código de ejemplo similar al suyo.

Resolví algo simular creando 2 propiedades:

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

El ModuleIDstring convierte su conjunto de valores en una lista y establece la propiedad ModuleIDs.

Esto también hará que los ModuleID se puedan usar desde un PropertyGrid, etc.

Ok, no es la mejor solución segura para escribir, pero para mí funciona.

pasar la lista del código detrás ...

aspx:

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

código subyacente:

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

uc.ModuleIds = list;

La forma en que normalmente hago esto es hacer que la propiedad ajuste la colección ViewState. Se verá mejor si se puede hacer que funcione, pero esto hará el trabajo:

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

Creo que el problema es el conjunto {}. El convertidor de tipos desea cambiar el List<int> de nuevo en una cadena, pero CanConvertFrom() falla para <=>.

Puede pasarlo a una cadena y dividirlo en una coma para completar una variable privada. No tiene la bondad de la atribución, pero funcionará.

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

Creo que su mejor opción es hacer que su control de usuario tenga una propiedad de estilo DataSource.

Se toma la propiedad como un objeto y luego se realiza una comprobación de tipo con IList / IEnumerable / etc para asegurarse de que sea correcta.

Licenciado bajo: CC-BY-SA con atribución
No afiliado a StackOverflow
scroll top