Passer la liste int en tant que paramètre à un contrôle utilisateur Web
-
05-07-2019 - |
Question
Je souhaite transmettre une liste int (List) en tant que propriété déclarative à un contrôle utilisateur Web, comme suit:
<UC:MyControl runat="server" ModuleIds="1,2,3" />
J'ai créé un TypeConverter pour cela:
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);
}
}
Et puis ajouté l'attribut à ma propriété:
[TypeConverter(typeof(IntListConverter))]
public List<int> ModuleIds
{
get { ... }; set { ... };
}
Mais j'obtiens cette erreur au moment de l'exécution:
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.
Ma question est similaire à celle posée ici , mais la solution ne résout pas mon problème:
Mise à jour : j'ai trouvé une page qui résout le premier problème. J'ai mis à jour le code ci-dessus pour afficher mes correctifs. Le code ajouté est les méthodes CanConvertTo
et ConvertTo
. Maintenant, je reçois une erreur différente.:
Object reference not set to an instance of an object.
Cette erreur semble être indirectement causée par un élément de la <=> méthode.
La solution
Après avoir raccordé un débogueur à Cassini, je constate que la référence null provient en fait de System.Web.Compilation.CodeDomUtility.GenerateExpressionForValue, qui essaie fondamentalement d'obtenir une expression pour le tableau int [] que vous transmettez au constructeur List. . Comme il n'y a pas de descripteur de type pour le tableau int [], il échoue (et jette une référence null dans le processus, au lieu du & "; Ne peut pas générer l'exception de jeu de propriétés &" Qu'il devrait l'être).
Je n'arrive pas à trouver un moyen intégré d'obtenir une valeur sérialisable dans une liste < int > ;, alors je viens d'utiliser une méthode statique:
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);
}
}
Autres conseils
Bien que je ne puisse pas dire que j’ai une expérience particulière de cette erreur, d’autres sources indiquent que vous devez ajouter une conversion au type InstanceDescriptor. départ:
http://weblogs.asp.net/bleroy /archive/2005/04/28/405013.aspx
Qui fournit une explication des raisons ou bien:
http://forums.asp.net/p/1191839/2052438 .aspx # 2052438
Qui fournit un exemple de code similaire au vôtre.
J'ai résolu quelque chose de similaire en créant 2 propriétés:
public List<int> ModuleIDs { get .... set ... }
public string ModuleIDstring { get ... set ... }
La chaîne ModuleID convertit son ensemble de valeurs en liste et définit la propriété ModuleIDs.
Ceci rendra également les ID de module utilisables à partir d'un PropertyGrid, etc.
D'accord, ce n'est pas la meilleure solution typesafe, mais cela fonctionne pour moi.
transmettez la liste à partir du code derrière ...
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;
Normalement, je fais en sorte que la propriété enveloppe la collection ViewState. Votre chemin sera plus beau si vous pouvez le faire fonctionner, mais le travail sera fait:
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;
}
}
Je pense que le problème est l'ensemble {}. Le convertisseur de type veut changer le List<int>
retour dans une chaîne, mais CanConvertFrom()
échoue pour <=>.
Vous pouvez le transmettre à une chaîne et le séparer par une virgule pour renseigner une variable privée. N'a pas la gentillesse d'attribution, mais fonctionnera.
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)));
}
}
Je pense que votre meilleure option est de donner à votre contrôle utilisateur une propriété de style source de données.
Vous prenez la propriété en tant qu'objet, puis vérifiez le type par rapport à IList / IEnumerable / etc pour vous assurer qu'elle est correcte.