Announcement

Collapse
No announcement yet.

Probleme mit eigenen UserControl in Visual Studio - Serializable

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

  • Probleme mit eigenen UserControl in Visual Studio - Serializable

    Hallo zusammen,

    ich hoffte durch meine Anmeldung ein für mich aktuell nicht lösbares Problem erklärt und beseitigt zu bekommen.
    Ich versuche ein eigenes Steuerelement zu entwerfen, stoße aber auf Probleme bei der Entwurfszeit, wenn ich das Steuerelement in ein Projekt einbinde.

    Zunächst die Fehlermeldung:
    "Fehler bei der Codegenerierung für die Bildelemente-Eigenschaft. Der Typ "System.Windwos.Forms.Panel" in Assembly "System.Windows.Forms" ist nicht als serialisierbar gekennzeichnet".

    So sieht die Klasse des Navigationselementes aus:

    Code:
        [Designer("System.Windows.Forms.Design.ParentControlDesigner, System.Design", typeof(IDesigner))]
    
        public partial class Navigationskreis : UserControl
        {
            private Point[] punkte = { new Point(113,0), new Point(203,26), new Point(230,114), new Point(203,208),
                                   new Point(113,230), new Point(21,208), new Point(0,114), new Point(21,26) };
    
            public int anzahlElemente = 8;
    
            public PictureBox Hauptbild;
    
            private List<Panel> bildelemente = new List<Panel>();
    
            public List<Panel> Bildelemente
            {
                get
                {
                    return bildelemente;
                }
                set
                {
                    this.bildelemente = value;
                }
            }
    
            private List<Panel> inhaltselemente = new List<Panel>();
    
            private List<Panel> Inhaltselemente
            {
                get { return inhaltselemente; }
                set { inhaltselemente = value; }
            }
    
            public Navigationskreis()
            {
                InitializeComponent();
                Hauptinhalt.Controls.Add(Hauptknopf);
                Hauptknopf.Left = 0;
                Hauptknopf.Top = 0;
                Hauptinhalt.SendToBack();
                Tooltip.Visible = false;
    
                for (int i=0; i<anzahlElemente; i++)
                { 
                    Panel pb = new Panel();
                    pb.BackColor = Color.Transparent;
                    pb.Parent = Hauptknopf;
                    pb.BackgroundImage = XiveCC.Properties.Resources.Animalokinese;
                    pb.BackgroundImageLayout = ImageLayout.Stretch;
                    pb.Width = 70;
                    pb.Height = 70;
                    pb.Left = punkte[i].X;
                    pb.Top = punkte[i].Y;
                    
                    pb.Name = "AUSW" + i;
                    pb.Visible = false;
                    bildelemente.Add(pb);
    
                    Panel ip = new Panel();
                    ip.BackColor = Color.Transparent;
                    ip.Visible = true;
                    ip.Parent = Hauptknopf;
                    ip.BackgroundImage = XiveCC.Properties.Resources.KnopfLeer;
                    ip.BackgroundImageLayout = ImageLayout.Stretch;
                    ip.Width = 70;
                    ip.Height = 70;
                    ip.Left = 0;
                    ip.MouseClick += Angeklickt;
                    ip.Top = 0;
                    bildelemente[i].Controls.Add(ip);
                    ip.Name = "INHA" + i;
                    inhaltselemente.Add(ip);
    
                }
                Invalidate();
            }
    
            private void Angeklickt(object sender, EventArgs e)
            {
                Panel x = (Panel)sender;
                int nummer = Int32.Parse(x.Name.Substring(4));
                Hauptinhalt.BackgroundImage = bildelemente[nummer].BackgroundImage;
                for (int i = 0; i < anzahlElemente; i++)
                {
                    bildelemente[i].Visible = false;
                }
            }
    
            private void Hauptknopf_DragEnter(object sender, DragEventArgs e)
            {
                e.Effect = DragDropEffects.Move;
            }
    
            private void Hauptknopf_MouseClick(object sender, MouseEventArgs e)
            {
                if (e.Button == MouseButtons.Left)
                {
                    for (int i = 0; i < anzahlElemente; i++)
                    {
                        bildelemente[i].Visible = true;
                    }
                }
                if (e.Button == MouseButtons.Right)
                {
                    Tooltip.Visible = true;
                }
                
            }
    
            private void Tooltip_MouseClick(object sender, MouseEventArgs e)
            {
                Tooltip.Visible = false;
            }
        }
    Ich habe schon versucht, einige Dinge zu lesen und [Serializable] vor die Klasse zu schreiben, irgendwelche [hidden]-Tags zu setzen, aber für mich ist das an dieser Stelle nur Raterei, da ich nicht erfahren genug bin, um zu wissen, WAS ich da tue. Daher hoffe ich nicht nur auf eine Lösung, sondern auch auf eine Erklärung, die mich weiterbringt.

    Vielen Dank im Voraus,

    Oliver

  • #2
    Ein kurzer Nachtrag: Ich habe es zumindest hinbekommen (ohne es zu verstehen) dass das Property Bildelemente private sein muss, damit die Fehlermeldung verschwindet.
    Nun kann ich es nutzen, allerdings verliere ich den Nutzen, da ich gerne hätte, dass man die Bildelemente des Naviators zur Laufzeit (oder Entwicklungszeit) austauschen kann.
    Kann mir jemand hier helfen?

    Comment


    • #3
      Nun ja so einfach darf man Controls nicht einfach veröffentlichen. Die sind erstmal nicht serialisierbar.
      Was möchtest du genau erzielen? Code und Beschreibung sind etwas im Widerspruch. Du erzeugst z.B. Controls erst zur Laufzeit möchtest die aber schon zur Entwicklungszeit austauschen/ändern können? Das kann rein vom zeitlichen Ablauf nicht

      Was ich erraten kann ist das du
      a.) bei Bildelemente/Inhaltselemente den setter nicht willst (schließe ich daraus das anzahlElemente hart kodiert ist). Um die Controls in der Liste zu ändern brauchst du nur den getter. Man muss sie nur aus der Liste holen können um sie zu ändern die Liste selbst willst du aber offensichtlich nicht ändern. Das sollte das Serialisierungsproblem schon mal beseitigen da eine reine getter Property nicht serialisiert wird.
      b.) Du könntest jetzt die Controls in der Liste austauschen das hätte aber keinen Einfluss auf die Anzeige da sich damit nicht das Control in der Controls Collection von Hauptknopf(komischer Name für einen Container) mit ändert. In dieser Liste verbleibt das alte Control egal was du in deinen veröffentlichten Listen anstellst. Entweder du willst gar nicht die Controls austauschen, dann veröffentliche die nicht als List sondern zum Beispiel als ReadOnlyList. Die Liste ist dann nicht mehr änderbar aber die Elemente in der Liste natürlich weiterhin. Oder wenn du eigentliche nur eine(oder wenige) Properties der Panels gezielt ändern willst dann veröffentliche gezielt auch nur diese. Also wenn du zum Beispiel nur das Backgroundimage der Panels ändern willst veröffentliche nur eine List<Image> und mappe die Änderungen zurück in die Panels.

      Comment


      • #4
        Hallo Ralf,

        hatte ich irgendwie befürchtet :-)
        Hintergrund ist, dass ich gerne ein Navigationsinstrument bauen würde, welches eine flexible Anzahl an Knöpfen hat. Diese will ich ENTWEDER zur Entwicklungszeit schon über AnzahlElemente auswählbar machen, ODER ABER, wenn einfacher, erst zur Laufzeit.
        Hartkodiert habe ich es vorerst, damit ich sehen kann, ob das das Problem ist.
        Nun bin ich auch schon weiter, allerdings noch nicht ganz am Ziel.
        Aktuell sieht das Element so aus:

        Code:
        using System;
        using System.Collections.Generic;
        using System.Drawing;
        using System.Windows.Forms;
        using XiveCC.Hilfsklassen;
        
        namespace XiveCC
        {
        
            //[Designer("System.Windows.Forms.Design.ParentControlDesigner, System.Design", typeof(IDesigner))]
            public partial class Navigationskreis : UserControl
            {
                private int anzahlElemente = 12;
        
                public int AnzahlElemente
                {
                    get
                    {
                        return anzahlElemente;
                    }
                    set
                    {
                        this.anzahlElemente = value;
                        BilderAufbauen();
                    }
                }
        
        
                private PictureBox Hauptbild;
                
                private List<Panel> bildelemente = new List<Panel>();
        
                private List<Panel> Bildelemente
                {
                    get
                    {
                        return bildelemente;
                    }
                    set
                    {
                        this.bildelemente = value;
                    }
                }
        
                private List<String> texte = new List<String>();
        
                private List<String> Texte
                {
                    get
                    {
                        return texte;
                    }
                    set
                    {
                        this.texte = value;
                    }
                }
        
        
                private List<Panel> inhaltselemente = new List<Panel>();
        
                private List<Panel> Inhaltselemente
                {
                    get { return inhaltselemente; }
                    set { inhaltselemente = value; }
                }
        
            
                public Navigationskreis()
                {
                    InitializeComponent();
                    Hauptknopf.StateCommon.Image = ControlHelper.BildgrößeÄndern(XiveCC.Properties.Resources.KnopfLeer, 150,150);
                    Hauptinhalt.Controls.Add(Hauptknopf);
                    Hauptknopf.Left = 0;
                    Hauptknopf.Top = 0;
                    Hauptinhalt.SendToBack();
                    Hauptinhalt.Visible = true;
                    Hauptinhalt.BackgroundImage = null;
                    Text.Text = "";
                    SubText.Text = "";
                    BilderAufbauen();
                }
        
                private void BilderAufbauen()
                {
                    double winkel = 360;
                    double radius = ((double)this.Width) / 2.5;
        
                    if (anzahlElemente > 0)
                    {
                        winkel = 360 / anzahlElemente;
                    }
        
                    winkel = winkel / 180 * Math.PI;
        
                    for (int i = 0; i < anzahlElemente; i++)
                    {
                        Panel pb = new Panel();
                        pb.BackColor = Color.Transparent;
                        pb.Parent = Hauptknopf;
                        pb.BackgroundImage = XiveCC.Properties.Resources.Animalokinese;
                        pb.BackgroundImageLayout = ImageLayout.Stretch;
                        pb.Width = 80;
                        pb.Height = 80;
        
                        double x = radius * Math.Cos(winkel * i);
                        double y = radius * Math.Sin(winkel * i);
        
                        pb.Left = (int) x + (int) radius;
                        pb.Top  = (int) y + (int) radius;
        
                        pb.Name = "AUSW" + i;
                        pb.Visible = false;
                        bildelemente.Add(pb);
                        texte.Add("Standardtext");
        
                        Panel ip = new Panel();
                        ip.BackColor = Color.Transparent;
                        ip.Visible = true;
                        ip.Parent = Hauptknopf;
                        ip.BackgroundImage = ControlHelper.BildgrößeÄndern(XiveCC.Properties.Resources.KnopfLeer, pb.Width, pb.Height);
                        ip.BackgroundImageLayout = ImageLayout.Stretch;
                        ip.Width = pb.Width;
                        ip.Height = pb.Height;
                        ip.Left = 0;
                        ip.MouseClick += Angeklickt;
                        ip.Top = 0;
                        bildelemente[i].Controls.Add(ip);
                        ip.Name = "INHA" + i;
                        inhaltselemente.Add(ip);
        
                    }
                    Invalidate();
                }
        
                private void Angeklickt(object sender, EventArgs e)
                {
                    Panel x = (Panel)sender;
                    int nummer = Int32.Parse(x.Name.Substring(4));
                    Hauptinhalt.BackgroundImage = ControlHelper.BildgrößeÄndern(bildelemente[nummer].BackgroundImage, 150,150);
                    Text.Text = texte[nummer];
                    Hauptinhalt.Visible = true;
        
                    for (int i = 0; i < anzahlElemente; i++)
                    {
                        bildelemente[i].Visible = false;
                    }
                }
        
                private void Hauptknopf_MouseClick(object sender, MouseEventArgs e)
                {
                    if (e.Button == MouseButtons.Left)
                    {
                        for (int i = 0; i < anzahlElemente; i++)
                        {
                            bildelemente[i].Visible = true;
                        }
                    }
                }
        
                public void BildelementSetzen(Image neu, String text, int pos)
                {
                    if (pos < anzahlElemente)
                    {
                        bildelemente[pos].BackgroundImage = neu;
                        texte[pos] = text;
                    }
        
                }
            }
        }
        Wie angedeutet: Das Element tut, was es soll, zeigt mir den gerückten Button INNERHALB des Steuerelements an und ich kann zur LAUFZEIT die Anzahl der Knöpfe ändern und auch deren Bilder austauschen. So, wie es sein soll.
        Nun kommt das aaaaaber.... meine Logik der Anordnung im Kreis klappt nicht (ich wollte alle Knöpfe, ausgehend vom Mittelpunkt, kreisförmig um das Zentrum anordnen. Klappt für genau 12 Knöpfe, ändere ich die Zahl, verteilt er die Knöpfe nicht auf dem Kreis neu, sondern zeichnet lediglich die Differenz zwischen 12 und dem Wert nicht mehr. Außerdem weiß ich noch nicht, wie ich das OnCLick-Event der Form, die das Steuerelement einbindet, weitergibt.

        Comment


        • #5
          Du mußt die bisherigen Controls auch erst entfernen bevor du in BilderAufbauen neue erzeugst sonst stapelst du bei jedem Aufruf immer mehr Controls die alle angezeigt werden wollen.
          BilderAufbauen sollte eher so aussehen.

          [HIGHLIGHT=C#]private void BilderAufbauen()
          {
          int buttonsize = 80;

          Hauptknopf.Controls.Clear();
          bildelemente.Clear();
          inhaltselemente.Clear();

          if(anzahlElemente == 0)
          return;

          try
          {
          Hauptknopf.SuspendLayout();
          SuspendLayout();

          double winkel = 2d * Math.PI / (double)anzahlElemente;
          double radius = ((double)(this.Width - buttonsize)) / 2d;

          for (int i = 0; i < anzahlElemente; i++)
          {
          // hier den Rest der Logik
          }
          // kein Invalidate!
          }
          finally
          {
          Hauptknopf.ResumeLayout(true);
          ResumeLayout(true);
          }
          }[/HIGHLIGHT]

          Comment


          • #6
            Wow, vielen lieben Dank.
            Kannst du mir als Letztes noch einen Tipp geben, wie ich das Event veröffentliche? Also wie die Form selbst auf das MouseClick-Event reagieren kann?

            Comment


            • #7
              In Angeklickt() einfach selbst nochmal einen Event werfen den dein UserControl veröffentlicht. Auf der Form dann halt diesen Event fangen und auswerten.
              Beispielhaft habe ich mal ein paar Daten mit den EventArgs rausgeschleust.

              [HIGHLIGHT=C#]public event EventHandler<ElementClickedArgs> ElementClicked;

              private void Angeklickt(object sender, MouseEventArgs e)
              {
              Panel x = (Panel)sender;
              int nummer = Int32.Parse(x.Name.Substring(4));
              Hauptinhalt.BackgroundImage = ControlHelper.BildgrößeÄndern(bildelemente[nummer].BackgroundImage, 150, 150);
              Text.Text = texte[nummer];

              EventHandler<ElementClickedArgs> ev = ElementClicked;
              if (ev != null)
              {
              // hier den Event Aufrufen, Daten übergeben und anschließend wieder rausklauben
              var args = new ElementClickedArgs() { Text = Text.Text, Nummer = nummer, Image = Hauptinhalt.BackgroundImage };
              ElementClicked(sender, args);
              Hauptinhalt.BackgroundImage = args.Image;
              Text.Text = args.Text;
              }

              Hauptinhalt.Visible = true;
              for (int i = 0; i < anzahlElemente; i++)
              bildelemente[i].Visible = false;
              }

              public class ElementClickedArgs : EventArgs
              {
              public int Nummer { get; set; }
              public Image Image { get; set; }
              public string Text { get; set; }
              }[/HIGHLIGHT]

              Comment


              • #8
                Guten Morgen Ralf,

                vielen Dank für diese Lösungen. Ich muss sagen, dass ich es erstaunlich finde, sich so in ein Projekt eines Anderen hineinversetzen zu können. Ich habe beruflich viel mit (Vollzeit-)Programmierern zu tun und weiß, dass das nicht so einfach ist, gerade wenn es nicht "so verständlich" ist oder "sich zu widersprechen" scheint.

                Es klappt, hatte was Erklärendes, war nicht unangenehm belehrend und freundlich, super, danke.
                Der Nachteil natürlich: Ich werde wohl nicht das letzte Mal Rat erbeten haben :-)

                Oliver

                Comment

                Working...
                X