Frage

Ich mag eine int-Liste (Liste) als deklarative Eigenschaft auf eine Web-Benutzer der Kontrolle wie folgt weitergeben müssen:

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

Ich habe einen Typeconverter, dies zu tun:

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 dann hinzugefügt, um das Attribut meiner Eigenschaft:

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

Aber ich bekomme diese Fehlermeldung 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 ein gefunden , aber die Lösung ist mein Problem nicht lösen:

Update: finde ich eine Seite, die das erste Problem gelöst. Ich aktualisiert den Code oben meine Korrekturen zu zeigen. Der hinzugefügte Code ist die CanConvertTo und ConvertTo Methoden. Jetzt bekomme ich einen anderen Fehler.

Object reference not set to an instance of an object.

Dieser Fehler scheint durch etwas in der ConvertTo Methode indirekt verursacht werden.

War es hilfreich?

Lösung

Nach einem Debugger in Cassini Einhaken, sehe ich, dass die Null ref tatsächlich von System.Web.Compilation.CodeDomUtility.GenerateExpressionForValue kommt, die im Grunde versucht, einen Ausdruck für die int zu erhalten [] Array, das Sie in die Liste Konstruktor . Da es für den int [] array kein Typdeskriptor ist, versagt es (und wirft einen Null-ref in dem Prozess, statt dem „nicht-Eigenschaft festgelegt Ausnahme erzeugen“, dass es soll).

Ich kann nicht herausfinden, über eine eingebaute Möglichkeit, einen serializable Wert in eine Liste der immer , so habe ich nur eine statische Methode:

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

Andere Tipps

Ich kann zwar nicht sagen, ich habe eine besondere Erfahrung mit diesem Fehler, zeigen andere Quellen, dass Sie eine Umstellung auf den Typ InstanceDescriptor hinzuzufügen. Check-out:

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

Welchen Beispielcode ähnlich wie bei Ihnen zur Verfügung stellt.

Ich löste etwas simular durch die Schaffung von zwei Eigenschaften:

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

Der ModuleIDstring wandelt seinen Wert auf eine Liste gesetzt und setzt die ModuleIDs Eigenschaft.

Dies wird auch die ModuleIDs nutzbar macht aus einem Property usw.

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

übergeben Sie die Liste aus dem Code hinter ...

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;

So wie ich dies normalerweise tun ist Eigentum zu machen, die Viewstate Sammlung wickeln. Ihr Weg sieht besser aus, wenn es an die Arbeit gemacht werden kann, aber dies wird den Job zu erledigen:

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

Ich glaube, das Problem ist die Menge {}. Der Typ Konverter wollen die List<int> zurück in einen String ändern, aber CanConvertFrom() nicht für List<int>.

Sie können es in einen String und Split auf Komma passieren eine private Variable zu füllen. Nicht die Genauigkeit der Zuordnung, aber funktioniert.

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

Ich denke, dass Sie die beste Wahl sind, ist Ihr Usercontrol eine Datasource-Stil hat zu machen.

Sie nehmen die Eigenschaft als Objekt und dann irgendeine Art gegen IList / IEnumerable / etc Kontrolle tun, um sicherzustellen, dass es korrekt ist.

Lizenziert unter: CC-BY-SA mit Zuschreibung
Nicht verbunden mit StackOverflow
scroll top