# Klasse wählen deren Titel mit einem String übereinstimmt, aber wie?



## Benni (10 November 2011)

Hi ihr,
ich habe mal wieder ein neues Problem in der C#-Programmierung, aber vielleicht habt ihr ja eine Idee und könnt mir helfen...

Und zwar habe ich 7 UserControls welche vom Titel bzw. von der Klassenbezeichnung her ähnlich sind, und zwar fangen alle mit "Adapterplatte_" an.
Nun soll in einem Panel je nach dem was in einer Textbox eingegeben wird die entsprechende Adapterplatte gewählt wird.
Ich habe es bisher so realisiert, dass ich den Text auf mit if Schleifen Abfrage und je nach dem was die Übereinstimmung ergibt die entsprechende Adapterplatte gewählt wird.
Da aber im laufe der Zeit noch weitere Adapterplatten hinzukommen können, wäre eine Schleifenabfrage durchaus übersichtlicher und schöner.
Ich weiß jedoch leider nicht ob dies überhaupt so zu realisieren ist.

Bisheriger Code:

string Adapterplatte=Textbox.Text;
Adapterplatte_MV15 Adapterplatte_MV15_1, Adapterplatte_MV15_2;
Adapterplatte_MV15_Siemens Adapterplatte_MV_Siemens_1, Adapterplatte_MV_Siemens_2;

if (Adapterplatte=="Adapterplatte_MV15")
{
Adapterplatte_MV15_1=new Adapterplatte_MV15();
panel_Prüfplatte1.Controls.Add(Adapterplatte_MV15_1);
Adapterplatte_MV15_2=new Adapterplatte_MV15();
panel_Prüfplatte2.Controls.Add(Adapterplatte_MV15_2 );
}

if (Adapterplatte=="Adapterplatte_MV15_Siemens")
{
Adapterplatte_MV_Siemens_1=new Adapterplatte_MV15_Siemens();
panel_Prüfplatte1.Controls.Add(Adapterplatte_MV_Siemens_1);
Adapterplatte_MV_Siemens_2=new Adapterplatte_MV15_Siemens();
panel_Prüfplatte2.Controls.Add(Adapterplatte_MV_Siemens_2 );
}

Und so weiter für die restlichen 5 oder 6 Prüfplatten eben auch so.

Ich habe mir eben so was vorgestellt wie

String Test = Adapterplatte.Replace(" ","_") + _1;

somit wäre dies die Bezeichnung der Klasse welche ich so benannt habe. Und ich könnte eine automatische Auswahl treffen


Gruß Benni


----------



## Lupo (10 November 2011)

Du könntest alle möglichen und vorhandenen Adapterplatten in eine Collection einfügen und die dann nach dem entsprechenden Element durchsuchen - ich könnte mir vorstellen, dass das so funktionieren könnte.


----------



## Jochen Kühner (10 November 2011)

Ich würde alle Adapterplatten von einem gemeinsamen Interface ableiter. Dann statts einer Textbox eine Combobox benutzen, in der alle in der Assembly vorhanden Klassen, welche von dem Interface ableiten gelistet werden (per Reflection, und vieleicht jeder Klasse noch ein Description Attribut zuordnen, für den Text in der Listbox. Mit einem button, wird dann eine Instanz des ausgewählten Typs erzeugt und der Liste hinzugefügt!


----------



## Benni (11 November 2011)

Hey ihr zwei, schon mal danke für eure Antworten,

@Lupo, was genau verstehst du unter einer Collection? Sorry, bin erst seit August in der C#-Programmierung tätig und habe von diesem Begriff leider noch nichts gehört.

@Jochen Kühner, also das mit der Textbox bzw. einer Variablen string muss fast sein, da ich diese Anhand von einer Artikelnummer befülle, es ist so dass wir in einer Liste verschiedene Artikelnummern haben, welche je nach dem eine bestimmte Ventilart sind und dementsprechend auf eine bestimmte Adapterplatte müssen... Diese Artikelnummern werden von einer Datei eingelesen und je nach dem welche gewählt wird, wird dann anhand des in der Datei stehenden Typs die entsprechende Adapterplatte in der Textbox bzw. Variablen angezeigt, sprich also die Adapterplatte ist abhängig von der eingegebenen Artikelnummer und wird nicht selbst direkt gewählt, also kann ich das eher nicht mit einer ComboBox realisieren... kannst du mir dennoch vielleicht ein paar Begriffe wie Reflection und so erklären und wo setzt man ein Description Attribut Kann ich dieses dann auch abfragen was hier drin steht und vergleichen o.ä.? 

Danke Euch beiden Vielmals
Gruß Benni


----------



## Benni (11 November 2011)

@ Lupo, also ich habe mich mal mit den Collections auseinandergesetzt.
Für die UserControls müsste ich ja dann also die ControlCollection verwenden das sehe ich doch richtig so oder?
Aber bei der deklaration muss ich ja die Üergeordnete Form angeben, nun habe ich hier aber das nächste Problem... Und zwar habe ich die UserControls mit dem ProjektmappenEditor dem Projekt hinzugefügt und somit besteht kein übergeordnetes Form, wie muss ich dies dann handhaben?


----------



## mkoenig (11 November 2011)

Wenn du die UserControls im ProjektMappenEditor hast musst du nur noch eine Referenz auf dein jetziges Projekt einfügen.

Jetzt kannst du die Controls mithilfe von "virtuellen" instanzen in eine neue ControlCollection packen und dann mit einer Schleife durchlaufen.

Anstatt der von mir verwendeten Controls (Button, Label,...) kannst du auch deine Usercontrols verwenden.

```
String testString = "Button"; // String in der Textbox

            // UserControls 
            PictureBox ctl1 = new PictureBox();
            Button ctl2 = new Button();
            Label ctl3 = new Label();

            // Neue ControlCollection
            ControlCollection ctls = new ControlCollection(new Form());
            ctls.Add(ctl1);
            ctls.Add(ctl2);
            ctls.Add(ctl3);


            // Checkroutine
            String ctlName = "";
            foreach (Control ctl in ctls)
            {
                ctlName = ctl.GetType().Name;

                if (ctlName == testString)
                {
                    ctl.Height = panel1.Height;
                    ctl.Width = panel1.Width;
                    
                    panel1.Controls.Add(ctl);
                }

            }
```


----------



## Benni (11 November 2011)

Hallo Manuel,
Danke für deinen Beitrag,
was verstehst du unter einer Referenz auf mein jetziges Projekt?
Kanns du mir das bitte kurz erläutern?


----------



## mkoenig (11 November 2011)

Ich hab mal kurz ein kleines Video gemacht. Das erklärt es vielleicht.
Hoffe du kannst es bei dir anschauen (am besten mit VLC).

Anhang anzeigen SelectByClassName.zip


----------



## Benni (11 November 2011)

Ne, leider kann ich diese net öffnen.
Naja aber ich hab es glaub ich hin bekommen... Aber kann ich danach auch irgendwie Variablen setzen, die in den einzelnen Klassen sind? Z.B. eine Artikelnummer oder so...

            Pruefplatte_MV15_1 = new Adapterplatte_MV15();
            Pruefplatte_MV15_2 = new Adapterplatte_MV15();
            Pruefplatte_MV15_Siemens_1 = new Adapterplatte_MV15_Siemens();

            ControlCollection Adapterplattensammlung = new ControlCollection(new Form());

            Adapterplattensammlung.Add(Pruefplatte_MV15_1);
            Adapterplattensammlung.Add(Pruefplatte_MV15_2);
            Adapterplattensammlung.Add(Pruefplatte_MV15_Siemens_1);


            foreach (Control ctl in Adapterplattensammlung)
            {
                Adapterplatte = Adapterplatte.Replace(" ", "_");
                if (Adapterplatte == ctl.GetType().Name)
                {
ctl.Artikelnummer = Artikelnummer;
                    panel_Pruefplatte1.Controls.Add(ctl);
                }   
            }


Das in Rot geschriebende würde ich gerne dann im nachhinein setzen... Damit ich die Collection gleich zu Beginn meines Codes setzen kann...


----------



## mkoenig (11 November 2011)

Ja du kannst diese Werte auch im nachhinein ändern.

Du musst allerdings wissen wie die Eigenschaft heißt die du ändern möchtest.
Bspw. bei einem Button möchtest du die Beschriftung setzen, somit brauchst du die Eigenschaft "Text".

Das sieht dann folgendermaßen aus.

```
// Checkroutine
            String ctlName = "";
            foreach (Control ctl in ctls)
            {
                ctlName = ctl.GetType().Name;

                if (ctlName == testString)
                {
                   [COLOR=#ff0000] // Eigenschaft des Controls holen
                    PropertyInfo pi = ctl.GetType().GetProperty("Text");

                    // Neuen Wert setzen
                    pi.SetValue(ctl, "Testme", null);[/COLOR]
                 
                    
                    ctl.Height = panel1.Height;
                    ctl.Width = panel1.Width;
                    
                    panel1.Controls.Add(ctl);
                }

            }
```


----------



## Benni (11 November 2011)

Hi Manuel,
also so wie du es beschrieben hast ging es nicht, dein Beitrag hat mir dennoch gut geholfen, habe es so realisiert:

 Type Typ = ctl.GetType();
                    Typ.GetField("Artikelnummer").SetValue(ctl, Artikelnummer);

leider habe ich gemerkt, dass es mich so nicht weiter bringt, da ich Anhand der Artikelnummer eine Tabelle mit daten füllen möchte und ich dies in einem Konstruktor mache, ich habe gesehen, dass es noch eine möglichkeit mit GetConstruktor gibt, ich weiß jedoch leider nicht wie ich diese Methode richtig verwenden muss um den Construktor erneut auszuführen...


----------



## mkoenig (11 November 2011)

Da bin ich jetzt auch etwas überfragt.
schau am besten mal in der MSDN nach oder bei StackOverflow bzw. CodeProject.
Dort findet man in der regel immer was.


----------



## Benni (11 November 2011)

Hey Leute, erstmal euch allen vielen Dank, ihr habt mir sehr geholfen.
Also ich habe demnach auch nun eine Lösung für mein Problem zurecht gebastelt...
Für die die es interessiert, hier ist sie:

ControlCollection Adapterplattensammlung = new ControlCollection(new Form());
Adapterplattensammlung.Add(new Adapterplatte_MV15());
Adapterplattensammlung.Add(new Adapterplatte_MV15());
Adapterplattensammlung.Add(new Adapterplatte_MV15_Siemens());
Adapterplattensammlung.Add(new Adapterplatte_MV15_Siemens());


int Prüplattennummer = 1; 
    // Zähler um auf die zweite Platte zu wechseln
foreach (Control ctl in Adapterplattensammlung)
{
    string Typenbezeichnung = Adapterplatte.Replace(" ", "_");
       //Aus der gewählten Adapterplatte die Leerzeichen löschen damit die Typenbezeichnung des UserControls entsteht
    if (Typenbezeichnung == ctl.GetType().Name)
    {
       Type Typ = ctl.GetType();
       Typ.GetConstructor(new Type[] { typeof(int) }).Invoke(ctl, new object[] { Artikelnummer });
       if (Prüplattennummer == 1)
          panel_Pruefplatte1.Controls.Add(ctl);
       if (Prüplattennummer == 2)
          panel_Pruefplatte2.Controls.Add(ctl);
       Prüplattennummer++;
    }
}


----------



## Benni (14 November 2011)

Guten morgen,
neues aber vielleicht ähnliches Problem:
Ich stelle in einem panel 32 Pictureboxen dar, falls einem die Zahl 32 bekannt vor kommt, genau es handelt sich um ein Kartenspiel ;-)

Auf jeden fall will ich es realisieren dass wenn man über die Karte fährt, sich diese etwas anhebt und beim verlassen der Karte sich diese wieder etwas senkt.

bisher habe ich das so gelöst, dass ich das MouseMove und das MouseLeave event benutze, jedoch dies wird relativ unübersichtlich wenn ich dies für jede einzelne picturebox so mache. Deshalb ist hier meine Frage, ob ich die picturebox bzw. deren Location auch allgemein setzen und abfragen kann?

Bisher habe ich dies so realisiert:

private void pictureBox_alle_Karten_erste_Haelfte_1_MouseMove(object sender, MouseEventArgs e)
        {
            pictureBox_alle_Karten_erste_Haelfte_1.Location = new Point(pictureBox_alle_Karten_erste_Haelfte_1.Location.X, y - 9);
        }
        private void pictureBox_alle_Karten_erste_Haelfte_1_MouseLeave(object sender, EventArgs e)
        {
            pictureBox_alle_Karten_erste_Haelfte_1.Location = aktuelle_pos;
        }

Aber wie gesagt dies für 32 oobjekte bzw. später wieder für 32 andere Objekte zu machen ist relativ aufwändig und Coderaubend...

Hat mir da jemand eine andere Lösung?
Zur Not würde ich auch eine neue Klasse (Karteicturebox) machen, wenn ich in ihr sagen könnte, MouseMove() und MouseLeave(), bin mir jedoch nicht sicher ob dies überhaupt geht...


----------

