Announcement

Collapse
No announcement yet.

Control als Element in einer Collection-Eigenschaft

Collapse
X
  • Filter
  • Time
  • Show
Clear All
new posts

  • Control als Element in einer Collection-Eigenschaft

    Hallo !

    Wenn ich in einem selbst erstellten Steuerelement eine Eigenschaft definiere, welche vom Typ Control abgeleitet ist, stellt das überhaupt kein Problem dar. Definiere ich jetzt aber die Eigenschaft als Collection vom selben Typ, erhalte ich beim Speichern die Fehlermeldung "der Typ ist nicht als serialisierbar deklariert".

    Ich hoffe, ich konnte das Problem einigermaßen verständlich rüberbringen.

    Was ich nicht verstehe, ist daß eine Eigenschaft vom Typ Control in einem Steuerelement funktioniert, in einer Collection-Eigenschaft aber nicht.

    Ich hoffe, es kann mir da jemand weiterhelfen, ich bin schon am Verzweifeln.

    Danke

  • #2
    Hallo Andreas,

    die Klassenreferenz in der .NET-Doku sagt, daß System.Windows.Forms.Control nicht serialisierbar ist. Damit sind auch die abgeleiteten Klassen nicht serialisierbar.

    Daran kannst Du als Entwickler nichts ändern, Microsoft müsste die Klasse Control als <serializable()> kennzeichnen.

    Es macht allerdings keinen Unterschied, ob die Klasse direkt serialisiert wird oder als Teil einer Collection. Eigentlich kann beides nicht funktionieren.

    Vielleicht kannst Du zu dem Problem ein bisschen Code posten.

    Klau

    Comment


    • #3
      Hallo Klaus !

      Hier ein kleines Code-Beispiel:

      public interface IControlParam
      {
      bool temp
      {
      get;
      set;
      }
      }

      public class TABCControl:Control,IControlParam
      {
      private bool Ftemp;

      public bool temp
      {
      get{return Ftemp;}
      set{Ftemp = value;}
      }

      }

      [TypeConverterAttribute(typeof(System.ComponentMode l.ExpandableObjectConverter))]
      [Serializable]
      public class TMyParam
      {
      private int FTempint;
      private IControlParam FControlParam;

      public int Tempint
      {
      get{return FTempint;}
      set{FTempint = value;}
      }

      public IControlParam ControlParam
      {
      get{return FControlParam;}
      set{FControlParam = value;}
      }

      }

      public class TMyControl:Control
      {
      private TMyParam FMyParam;

      public TMyControl()
      {
      FMyParam = new TMyParam();
      }

      public TMyParam MyParam
      {
      get{return FMyParam;}
      }
      }

      // Dieses Beispiel funktioniert einwandfrei

      /* Möchte ich jetzt allerdings MyParam aus TMyControl als Collection mit dem Typ TMyParam haben, kommt eben die Fehlermeldung "der Typ ist nicht als serialisierbar deklariert" (das bezieht sich auf den Typ TABCControl) sobald ich dem Parameter ControlParam einen Wert zuweise, und ich das Ganze speichern möchte. Wenn ich den typ TABCControl als serializable deklariere, kommt die gleiche Fehlermeldung allerdings mit dem Bezug auf Control.
      */

      // Das folgende Beispiel soll das verdeutlichen

      public class TMyParamCollection:CollectionBase,ICollection
      {
      public TMyParamCollection
      {
      }

      public TMyParam this[ int index ]
      {
      get{ return((TMyParam)List[index]);}
      set{List[index] = value;}
      }

      public int Add(TMyParam val)
      {
      return(List.Add(val));
      }

      public int IndexOf(TMyParam val)
      {
      return(List.IndexOf(val));
      }

      public void Insert(int index,TMyParam value)
      {
      List.Insert(index,value);
      }

      public void Remove(TMyParam value)
      {
      List.Remove(value);
      }

      public bool Contains(TMyParam value)
      {
      List.Contains(value);
      }
      }

      public class TMyParamCollectionPoperty:TMyParamCollection,IColl ection
      {
      private TMyParamCollection plist;

      public TMyParamCollectionPoperty(TMyParamCollection plist)
      {
      this.plist = plist;
      }

      public TMyParam this[int index]
      {
      get{return(plist[index])};
      set{plist[index] = value;}
      }

      protected override void OnInsert(int index,object value)
      {
      if(index == 0)
      {
      plist.Clear();
      }

      plist.Add((TMyParam)value);
      }

      protected override void OnSet(int index,object oldValue,object newValue)
      {
      plist[index] = (TMyParam)newValue;
      }

      protected override void OnRemove(int index,object value)
      {
      plist.RemoveAt(index);

      }

      protected override void OnClear()
      {
      plist.Clear();
      }

      }

      public class TMyControl:Control
      {
      private TMyParamCollection FParamList;

      public TMyControl()
      {
      FParamList = new TMyParamCollection();
      this.Icollection = new TMyParamCollectionPoperty(FParamList);
      }

      private TMyParamCollectionPoperty Icollection;
      [DesignerSerializationVisibility(DesignerSerializat ionVisibility.Content)]
      [EditorAttribute(typeof(System.ComponentModel.Desig n.CollectionEditor), typeof(System.Drawing.Design.UITypeEditor))]
      public TMyParamCollectionPoperty ParamList
      {
      get{return Icollection;}
      }
      }

      ---

      So, ich hoffe, ich habe das jetzt einigermaßen richtig geschrieben.

      Übrigens, mit diesen Formatierungsregeln für Quellcode, wie hier beschrieben komme ich nicht ganz klar. Funktionieren die wirklich

      Comment


      • #4
        Hallo Andreas,

        Damit eine Klasseninstanz zur Laufzeit tatsächlich serialisiert werden kann, müssen folgende Bedingungen erfüllt sein:

        - Die Klasse mus als [Serializable] gekennzeichnet sein.

        - Die Basisklasse dieser Klasse muss serialisierbar sein.

        - Alle Member der Klasse müssen serialisierbare Typen sein

        - Alle Objekte, die zur Laufzeit innerhalb einer Instanz der Klasse gespeichert sind (z.B. in einer Collection) müssen serialisierbar sein

        In Deinem Code sind

        - TMyParam : serialisierbar

        - TABCControl,TMyControl : nicht serialisierbar, da von Control abgeleitet. Control ist nicht serialisierbar.

        - TMyParamCollection, TMyParamCollectionPoperty : serialisierbar, da CollectionBase serialisierbar ist. Allerdings müssen sie in Deinem Code als [Serializable] gekennzeichnet werden, damit dies auch wirksam wird.

        Wenn Du zur Laufzeit eine Instanz von TMyParamCollection erzeugst, dann ist diese serialisierbar, solange sie keine nicht-serialisierbaren Elemente enthält. Wenn Du ein TABCControl hineinsteckst, dann löst dies einen Laufzeitfehler aus, weil dieses Element nicht serialisierbar ist.

        Klau

        Comment


        • #5
          Hallo Klaus !

          Was du da geshrieben hast, leuchtet mir ein, und ich habe das auch urprünglich so verstanden.
          Das Serializable bei der Collection hatte ich hier vergessen zu schreiben.

          Trotzdem ist mir jetzt immer noch nicht klar, warum Variante 1 (ohne Collection) funktioniert, und Variante 2 (mit Collection nicht).
          Ich sollte noch erwähnen, daß die Fehlermeldung "der Typ ist nicht als serialisierbar deklariert" nur erscheint, sobald ich ControlParam aus TMyParam einen Wert zuweise (und zwar nur bei der Collection-Variante). Solange der ControlParam null ist, gibt's auch mit der Collection keine Probleme.
          Weiters erscheint mir seltsam, daß die Fehlermeldung sich auf Control bezieht, wobei ja IControlParam gar nix mit Control zu tun hat.
          Oder orientiert sich die Serialisierbarkeit an der tatsächlich zugewiesenen Objektinstanz, und nicht am Typ IControlParam. Ich habe nämlich in meinem Versuch MyParam.ControlParam eine Instanz vom Typ TABCControl zugewiesen, der ja von Control abgeleitet ist. Ich dachte mir aber, daß hier nur der Teil, der in IControlParam definiert ist als Eigenschaft gilt, und nicht der ganze TABCControl. Doch in diesem Fall dürfte dann aber auch TMyParam nicht serialisiert werden können.

          Es ist jetzt aber so, daß TMyParam serialisert werden kann, TMyParamCollectionProperty jedoch nicht (natürlich nachdem diese als Serializable deklariert wurde).
          Oder bin ich jetzt einfach zu dämlich, deinen Ausführungen folgen zu können.

          Laut deinen Ausführungen müßten ja sowohl TMyParam als auch TMyParamCollectionProperty serialisierbar sein. Warum ist es dann TMyParamCollectionProperty nicht ?

          Ich hoffe , ich konnte einigermaßen rüberbringen, worauf ich hinaus will.

          Vielleicht kannst du mir da noch einmal helfen, warum es diesen Unterschied zwischen TMyParam und TMyParamCollectionProperty gibt.

          Vielen Dan für deine Hilfe,

          andrea

          Comment


          • #6
            Hallo Andreas,

            die Serialisierung dient in .NET u.a. zur Übertragung von Objekten über das Netzwerk, z.B. beim Aufruf von Webservices oder beim RPC.

            Daher müssen beim Serialisieren alle Informationen "eingepackt" werden, die beim Deserialisieren des Objektes benötigt werden, um den Ausgangszustand exakt wiederherzustellen.

            Die Serialisierung bearbeitet dazu den Objektgraphen rekursiv. Für alle Properties und Variablen eines Elementes (egal ob public oder private) wird die Serialisierung dem jeweiligen Typ entsprechend durchgeführt.

            Wenn also eine Collection serialisiert wird, dann wird zuerst die Collection selbst bearbeitet und dann die einzelnen Objekte, die in der Collection aktuell enthalten sind. Wenn die (an sich serialisierbare) Collection ein nicht-serialisierbares Objekt enthält, dann wird der Laufzeitfehler durch dieses Element ausgelöst.

            Daran liegt es, daß sich der Laufzeitfehler in Deinem Programm auf Control bezieht. Das ist der Typ, der nicht serialisierbar ist. Diese Tatsache lässt sich auch in abgeleiteten Klassen (TABCControl) nicht ändern.

            .NET kann übrigens sowohl binär als auch SOAP formatieren. Das eröffnet die Möglichkeit, das serialisierte Objekt im Detail mit einem XML-Viewer anzusehen.

            Der folgende Code erzeugt ein ListDictionary und füllt es mit einem DateTime-Objekt und einem String. Danach wird es mit dem SOAP-Formatter serialisiert und in einer Datei gespeichert. Das Ergebnis ist zwar nicht ganz einfach zu lesen, aber interessant ;-)

            /// Begin code snippet

            using System;

            using System.Collections;

            using System.Collections.Specialized;

            using System.Runtime.Serialization.Formatters.Soap;

            using System.IO;

            namespace ConsoleApplication1

            {

            class Class1

            {

            [STAThread]

            static void Main(string[] args)

            {

            FileStream _fs = File.Create("c:/SOAPtest.dat");

            SoapFormatter serializer = new SoapFormatter();

            ListDictionary ObjectToStore = new ListDictionary();

            DateTime dt = DateTime.Now;

            ObjectToStore.Add("Element1",dt);

            string s ="Teststring";

            ObjectToStore.Add("Element2",s);

            serializer.Serialize(_fs, ObjectToStore);

            _fs.Close();

            }

            }

            }

            /// End code snippet

            Als Consolen-Anwendung in VS.NET anlegen und einen Verweis auf System.Runtime.Serialization.Formatters.Soap hinzugefügen.

            Schöne Grüße,

            Klau

            Comment


            • #7
              Hallo Klaus !

              Vielen Dank für deine Geduld mit mir. Für mich war es einfach nicht nachvollziehbar.

              Ich glaube ich habe es jetzt einigermaßen verstanden.

              Andrea

              Comment

              Working...
              X