12 Stimmen

Übergabe einer int-Liste als Parameter an eine Web-Benutzersteuerung

Ich möchte eine int-Liste (Liste) als deklarative Eigenschaft an ein Web-Benutzer-Steuerelement wie folgt übergeben:

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

Zu diesem Zweck habe ich einen TypeConverter erstellt:

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

Und fügte dann das Attribut zu meiner Eigenschaft hinzu:

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

Aber ich erhalte diesen Fehler zur Laufzeit:

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.

Meine Frage ist ähnlich wie die folgende aquí , aber die Lösung löst mein Problem nicht:

Aktualisierung: Ich habe eine Seite gefunden, die das erste Problem gelöst hat. Ich habe den Code oben aktualisiert, um meine Korrekturen zu zeigen. Der hinzugefügte Code ist der CanConvertTo y ConvertTo Methoden. Jetzt bekomme ich einen anderen Fehler..:

Object reference not set to an instance of an object.

Dieser Fehler scheint indirekt durch etwas in der ConvertTo Methode.

10voto

Mark Brackett Punkte 83046

Nachdem ich einen Debugger in Cassini eingehängt habe, sehe ich, dass die Null-Referenz tatsächlich von System.Web.Compilation.CodeDomUtility.GenerateExpressionForValue kommt, die im Grunde versucht, einen Ausdruck für das int[]-Array zu erhalten, das Sie an den List-Konstruktor übergeben. Da es keinen Typ-Deskriptor für das int[]-Array gibt, schlägt es fehl (und wirft eine Null-Referenz in den Prozess, statt der "kann nicht generieren Property Set Ausnahme", die es sollte).

Ich kann keinen eingebauten Weg finden, um einen serialisierbaren Wert in eine List<int> zu bekommen, also habe ich einfach eine statische Methode verwendet:

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

1voto

Brian B. Punkte 1779

Ich kann zwar nicht sagen, dass ich besondere Erfahrungen mit diesem Fehler habe, aber andere Quellen weisen darauf hin, dass Sie dem Typ InstanceDescriptor eine Konvertierung hinzufügen müssen. siehe:

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

Die eine Erklärung der Gründe liefert oder alternativ:

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

Dort finden Sie einen ähnlichen Beispielcode wie den Ihren.

1voto

GvS Punkte 51365

Ich habe etwas Ähnliches gelöst, indem ich 2 Eigenschaften erstellt habe:

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

Der ModuleIDstring wandelt seine Wertemenge in eine Liste um und legt die ModuleIDs-Eigenschaft fest.

Dadurch werden die ModuleIDs auch in einem PropertyGrid usw. verwendbar.

Ok, nicht die beste, typsichere Lösung, aber für mich funktioniert es.

0voto

craigmoliver Punkte 6383

Die Liste aus dem Code dahinter weitergeben...

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;

0voto

Simon Johnson Punkte 7722

Normalerweise mache ich das so, dass die Eigenschaft die ViewState-Sammlung umhüllt. Ihr Weg sieht besser aus, wenn es gemacht werden kann, um zu arbeiten, aber dies wird die Arbeit erledigt:

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

CodeJaeger.com

CodeJaeger ist eine Gemeinschaft für Programmierer, die täglich Hilfe erhalten..
Wir haben viele Inhalte, und Sie können auch Ihre eigenen Fragen stellen oder die Fragen anderer Leute lösen.

Powered by:

X