c# asp.net typeconverter

c# - Pasar la lista int como parámetro a un control de usuario web



asp.net typeconverter (8)

Quiero pasar una lista int (Lista) como una 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 obtengo 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 la que se encuentra aquí , pero la solución no resuelve mi problema:

Actualización: encontré una página que resolvió el primer problema. Actualicé el código anterior para mostrar mis correcciones. El código agregado es los métodos CanConvertTo y ConvertTo . Ahora recibo un error diferente .:

Object reference not set to an instance of an object.

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


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


Creo que tu mejor opción es hacer que tu usercontrol tenga una propiedad de estilo DataSource.

Toma la propiedad como un objeto y luego realiza una verificación de tipo contra IList / IEnumerable / etc para asegurarse de que sea correcta.


La forma en que normalmente hago esto es hacer que la propiedad ajuste la colección ViewState. Tu camino se ve mejor si se lo puede hacer funcionar, 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; } }


Puede pasarlo a una cadena y dividir en coma para poblar una variable privada. No tiene la calidad 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))); } }



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

aspx:

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

código detrás:

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


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

No puedo encontrar una forma integrada de obtener un valor serializable en una lista <int>, así que acabo de utilizar 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); } }


Resolví algo simular creando 2 propiedades:

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

El ModuleIDstring convierte su valor establecido en una lista y establece la propiedad ModuleIDs.

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

De acuerdo, no es la mejor solución segura para la seguridad, pero para mí funciona.