Autor Beitrag
Glowhollow
ontopic starontopic starontopic starontopic starontopic starontopic starontopic starhalf ontopic star
Beiträge: 77



BeitragVerfasst: Mi 03.04.19 15:31 
Hallo !

Sorry das ich nochmal stören muß. Ich bin gerade dabei eine VB Anwendung in C# zu portieren, stoße hier jedoch auf kleinere Probleme.

Soweit ich das festgestellt habe, gibt es in VB wohl globale Instanzen der Forms, welche so in der Form in C# erst nach dem Instanzieren der Fall ist. Auch das Ansprechen der Unterelemente der Forms scheint hier anders zu sein als in C#.

Wie ist denn die best Practice mit Windows Forms, wenn ich mehrere habe, und diese untereinander irgendwelche Daten ändern ?

Im moment habe ich es so, das ich z.bsp. einen Splashscreen habe, wo man sich einloggen kann, danach wird eine andere Form aufgerufen.

Ich würde das gerne so handhaben, das ich nach der Initialisierung und Instanzierung von splashscreen, elemente in der main form ändern kann (bidirektional). Zudem ändert wiegesagt splashscreen, z.bsp. den namen eines Buttons (textfeld) in der main form.

Kann mir hier jemand tipps geben ?

Moderiert von user profile iconTh69: Beiträge zusammengefasst

Gut, hier eine ausführliche Variante.

Vielleicht hilft ein kleines Beispiel.

Angenommen, ich habe 2 Forms, mit jeweils 1 Button. Drücke ich Form 1, soll in Form 2 der name des Buttons sich ändern. Und umgekehrt.

Was sind die Vorraussetzungen ? (klar instanziert)

Da ich ursprünglich aus der ActionScriptSzene komme und seit gut nem halben Jahr mit C# rummache (sehr schöne sprache), aber so noch nie mit WinForms gearbeitet habe, hier eine kurze Analogie.
In Flash konnte man z.bsp. ein Fenster designen (so wie es in mit dem Designer in Visual Studio möglich ist). Gut, in flash hatte man mehr Möglichkeiten, aber das lasse ich mal aussen vor.
es gabe stage und root. Über root konnte man alle instanzierten Elemente ansprechen. Schreibweise war z.bsp. _root.button.textfeld

Ich würde gerne ähnliches in C# machen. Da ich es jetzt verstanden habe, das ich in C# die WinForms erst mal instanziert haben muß, um Elemente da drin anzusprechen.
Mein momentan Workflow wäre, ich logge mich auf dem splashscreen ein, geb mein username passwort ein, und danach öffnet sich das hauptfenster.

Wenn ich das richtig verstanden habe, müssen aber bevor ich überhaupt zwischen den Forms daten ändern kann, diese erst mal instanzieren.
Bedeutet das, das erst mal alle Forms "sichtbar" sind ? und ich die einzeln ein und ausblenden muß ?
wie wäre denn die vorgehensweise, wenn ich form 1 habe, das dann form 2 aufruft, form1 ist dann aber nicht mehr sichtbar, nach dem aufruf und so weiter.
Und wie soll ich referenzieren, wenn nicht mal das objekt vorhanden ist, im codeeditor ?

Ich stehe hier etwas auf dem schlauch.
Moderiert von user profile iconTh69: Code-Tags hinzugefügt
Moderiert von user profile iconTh69: Leerzeilen entfernt.
Chiyoko
ontopic starontopic starontopic starontopic starontopic starontopic starontopic starontopic star
Beiträge: 298
Erhaltene Danke: 8

Win 98, Win Xp, Win 10
C# / C (VS 2019)
BeitragVerfasst: Mi 03.04.19 16:08 
Ich habe dir in deinem anderen zuvor erstellten Thread was geschrieben aber du hast deine Frage in diesem Moment wieder zurück gezogen.
Den Weg seh ich als den saubersten als Kommunikation zwischen den Forms an, denn die Formulare kennen sich gegenseitig nicht.

Du schreibst aber in deinem Beispiel, auf jegliche Formen zugreifen zu wollen.
Dazu würde ich mir eine Art Lookup basteln (ein Dictionary deiner instanzierten Forms gewissermaßen).

Zitat:
Wenn ich das richtig verstanden habe, müssen aber bevor ich überhaupt zwischen den Forms daten ändern kann, diese erst mal instanzieren.

Bedeutet das, das erst mal alle Forms "sichtbar" sind ? und ich die einzeln ein und ausblenden muß ?


Das ist Teil von OOP Wissen und damit Grundlagenwissen von C#. Im Forum gibt es eine Menge Threads darüber.
Eine Form ist auch nur ein Objekt. Um auf Variablen eines Objektes zugreifen zu können, muss eine Instanz existieren.
(Ausnahmen bilden Structs, also Value Typen. Die müssen nicht instanziert werden).

Wenn du nur Daten übergeben willst, bietet sich der Konstruktor an.
ausblenden C#-Quelltext
1:
2:
Form frm  = new Form(Passwort);
frm.ShowDialog();


Moderiert von user profile iconTh69: Beitrag aus dem anderen Thema hierher kopiert:

Sauber wäre z.b. die Nutzung eines Interfaces.

Beispielausschnitt:
ausblenden volle Höhe C#-Quelltext
1:
2:
3:
4:
5:
6:
7:
8:
9:
10:
11:
12:
13:
14:
15:
16:
17:
18:
19:
20:
21:
22:
23:
24:
25:
26:
27:
28:
29:
30:
31:
32:
33:
34:
35:
36:
37:
38:
39:
40:
41:
42:
43:
44:
45:
        IUserControl _activeUserControl;

        private IUserControl CreateUserControl(Type userControl)
        {
            UserControl ctrl = (UserControl)Activator.CreateInstance(userControl);
            Type iuc = userControl.GetInterface("IUserControl");
            if (iuc != null)
            {
                panUserControlType.Controls.Add(ctrl);
                ctrl.Dock = DockStyle.Fill;
                ctrl.Parent = panUserControlType;

                return (IUserControl)ctrl;
            }
            else
                return null;
        }

        public async void CreateUserControl(UserControlType ucType)
        {
            try
            {
                if (_activeUserControl != null)
                {
                    _activeUserControl.SaveSettings();

                    _activeUserControl.Dispose();
                    _activeUserControl = null;
                }

                switch (ucType)
                {
                    case UserControlType.About:
                        _activeUserControl = CreateUserControl(typeof(FrmPartAbout));
                        break;
                }

                lblUserControlType.Text = _activeUserControl.UcText;
                picUserControlType.Image = _activeUserControl.UcImgage;
            }
            catch(Exception ex)
            {
                _log.Error($"Fehler beim Erstellen eines UserControls vom Type {ucType.GetType()}", ex);
            }
        }
Ralf Jansen
ontopic starontopic starontopic starontopic starontopic starontopic starontopic starhalf ontopic star
Beiträge: 4700
Erhaltene Danke: 991


VS2010 Pro, VS2012 Pro, VS2013 Pro, VS2015 Pro, Delphi 7 Pro
BeitragVerfasst: Mi 03.04.19 17:11 
Ein guter Ansatz ist zwischen den Daten und der Darstellung der Daten zu unterscheiden. Dann ergibt sich z.b. das Problem nicht das 2 Formen miteinander sprechen müssen. Jede Form liest oder ändert nur die Daten.

Dazu würdest du erstmal ein Klasse/oder Klassen erstellen die die Daten unabhängig von der Darstellung abstrakt darstellt. Das nennt man üblicherweise ein Model.
In dem Fall wo, wie du sagst ein Form eine andere ändert, wäre es in meiner Darstellung so das sich die zwei Formen einfach das gleiche Model teilen.

Heißt wenn auf Form 1 sich was ändert dann schreib diese Änderung in das Model. Die 2.te Form die die gleiche Model Instanz benutzt muss das mitbekommen und entsprechen reagieren (dabei helfen z.B. Events im Model die geworfen werden wenn es sich ändert und auf die eine Form reagieren kann). Der Ablauf ist also

Änderung in Form 1 -> Anderung in Modelklasse -> Reaktion in Form 2
Glowhollow Threadstarter
ontopic starontopic starontopic starontopic starontopic starontopic starontopic starhalf ontopic star
Beiträge: 77



BeitragVerfasst: Mi 03.04.19 17:41 
Jo, MVC ist mir n Begriff.

Gut, kurz noch ein paar Fragen klären, da ich mit WindowsForm so in der Form noch nicht gearbeitet habe.

Die Form wird ja mit

ausblenden Quelltext
1:
2:
3:
Application.EnableVisualStyles();
Application.SetCompatibleTextRenderingDefault(false);
Application.Run(new splashscreen());


aufgerufen.

In visualbasic, war die ganze logik in der Forms selbst mit enthalten. Das kann ich doch in das MVC Pattern auslagern. Was ich jetzt noch nicht so ganz verstehe ist, ist dieser Application Aufruf. Ist das schon eine Instanzierung ?

Ich dachte instantieren würde ich mit new... (ok, sehe gerade 3. Zeile = new splashscreen();)

das heißt, ich kann mvc pattern über splashscreen (klasse) - die properties, der einzelnen elemente ändern ?

Ich probier mal rum, habs noch nicht getestet...

[NACHTRAG]:

Habe jetzt versucht auf einen Button Event zu reagieren.

in der Form selbst, wird ja vom designer folgender Block (hier ein button) hinzugefügt.

ausblenden Quelltext
1:
2:
3:
4:
5:
6:
7:
8:
9:
10:
11:
this.sfButton1.AccessibleName = "Button";
this.sfButton1.BackColor = System.Drawing.Color.White;
this.sfButton1.Font = new System.Drawing.Font("Segoe UI Semibold", 9F);
this.sfButton1.Location = new System.Drawing.Point(330, 319);
this.sfButton1.Name = "sfButton1";
this.sfButton1.Size = new System.Drawing.Size(96, 60);
this.sfButton1.Style.BackColor = System.Drawing.Color.White;
this.sfButton1.TabIndex = 34;
this.sfButton1.Text = "Anmelden";
this.sfButton1.UseVisualStyleBackColor = false;
this.sfButton1.Click += new System.EventHandler(this.sfButton1_Click);


Sollte ich hier nicht über die Main - den button ansprechen können ?

Ok, habe etwas recherchiert, aber noch nicht so ganz verstanden. Da ja hier nur ein Objekt erzeugt wird, ist nicht automatisch eine Referenz dazu da.

Wie komme ich aber jetzt an die Referenz z.bsp. von this.sfButton1.Text ?
Ralf Jansen
ontopic starontopic starontopic starontopic starontopic starontopic starontopic starhalf ontopic star
Beiträge: 4700
Erhaltene Danke: 991


VS2010 Pro, VS2012 Pro, VS2013 Pro, VS2015 Pro, Delphi 7 Pro
BeitragVerfasst: Mi 03.04.19 20:47 
Zitat:
Wie komme ich aber jetzt an die Referenz z.bsp. von this.sfButton1.Text ?

In der Main Methode kannst du die Form auch einfach an einer Variablen erzeugen und dann die Variable an Application.Run übergeben.
ausblenden C#-Quelltext
1:
2:
var splash = new splashscreen();
Application.Run(splash);

Aber es wird dir voraussichtlich nicht helfen :wink:

Dazu muss man etwas ausholen und Application.Run erklären. Stell dir am besten vor das dein ganzer Programmablauf in Application.Run stattfindet. Jetzt wo du die splash Variable hättest kannst du nur vor Application.Run darüber auf den SplashScreen zugreifen oder danach. Also bevor der SplashScreen angezeigt wird (auch das passiert in Application.Run) oder nachdem die geschlossen wurde. Heißt zum Ende deines Programms was vermutlich zu spät ist um irgendwas sinnvolles mit den Daten/Informationen die du aus dem SplashScreen holen könntest anzustellen. Das was man an Application.Run übergibt ist logisch das Element das die Lebenszeit der Anwendung steuert und man will natürlich während der Lebenszeit der Anwendung etwas tun :wink:

Das was du tun willst muss also mit aller Wahrscheinlichkeit während Application.Run passieren. Das mit dem Splashscreen ist der übliche Fall an dem man merkt das das Winforms Standardverhalten hier nicht passt. Es gibt nicht eine Form die die Lebenszeit der Anwendung steuert sondern mindestens 2. Denn den SplashScreen will man zeitlich vor einer anderen Form darstellen. Man kann natürlich versuchen irgendwas zu zaubern indem man die eine Form von der anderen aus erzeugt und eine Form dann vorübergehend versteckt hält. Das haben aber schon viele versucht um so das gewünschte Verhalten hinzubekommen. Ist aber nicht trivial wenn man mit diversen glitches in die man da reinläuft nicht leben möchte. Man kommt schnell in Focus Probleme wenn die Formen wechseln tut sich schwer Formen die man eigentlich n icht mehr braucht freizugeben etc.

Es gibt aber Alternativen. Wenn du dir die Application.Run Methode mal ansiehst wirst du sehen das es Überladungen gibt die keine Form annehmen sondern einen ApplicationContext. Das ist die eigentlich relevante Klasse in diesem Konstrukt. Die steuert die Lebenszeit der Anwendung, hält die MessageQueue zur Kommunikation der Anwendung mit Windows und etliches anderes. Die Standardüberladung die du in der Main gefunden hat geht eigentlich auch nur hin und erzeugt einen ApplicationContext mit der übergebenen Form und ruft die Run Variante mit dem ApplicationContext auf.

Ein Beispiel das einen eigenen ApplicationContext zeigt um einen Splashscreen und eine weitere Form nacheinander anzuzeigen findest du hier. Das ist wirklich nur ganz simpel und zeigt die Splashform über einen Timer eine zeit lang an und danach die andere Form.

Wenn du noch weitere Beispiel suchst mit "Application.Run Splash ApplicationContext" solltest du einige weitere Beispiel im Netz finden.

Zu der Frage mit dem Button und wie du daran kommst gehe ich jetzt erstmal nicht groß ein. Ist eigentlich auch die falsch Richtung. Wir hatten ja schon bemerkt das die Daten in ein Model gehören und wenn man das erstmal hat und das zwischen den Formen teilt muss niemand mehr von außen auf Controls zugreifen.
Glowhollow Threadstarter
ontopic starontopic starontopic starontopic starontopic starontopic starontopic starhalf ontopic star
Beiträge: 77



BeitragVerfasst: Fr 05.04.19 09:15 
Hallo Ralf !

Danke für die Hilfestellung.

Ich checks jedoch nicht ganz.

Habe versucht das ganze zu adaptieren und erst mal nur mit 2 Forms zu arbeiten (ingesamt sinds 4).

Ich habe 2 Forms, Form1(auch main_form intern genannt), splashcreen(intern splashcreen). Ich habe die db-verbindungsgeschichte in eine eigene klasse ausgelagert, ebenso, die Main, hier Program.cs genannt. Diese dient als entry. Gesteuert wird das ganze über die form_main.cs

In der Program.Cs habe ich folgendes stehen

ausblenden C#-Quelltext
1:
2:
3:
4:
5:
6:
7:
8:
9:
10:
11:
12:
13:
14:
15:
16:
17:
18:
19:
20:
21:
22:
23:
24:
25:
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using System.Windows.Forms;

namespace GDISClient
{
    public class Program : ApplicationContext
    {
        Form mainForm = null;
        private static void Main(string[] args)
        {
            Program context = new Program(new Form1(), new splashscreen());

            Application.Run(context);
        }

        public Program(Form mainForm, Form splashForm) : base(splashForm)
        {
            this.MainForm = mainForm;
        }
    }
}


Form 1 enthält folgenden auszug...
ausblenden C#-Quelltext
1:
2:
3:
4:
5:
6:
7:
8:
9:
10:
11:
12:
13:
14:
15:
16:
17:
18:
19:
using...
namespace GDISClient
{
    public partial class form_main : Form
    {
        /// <summary>
        /// Required designer variable.
        /// </summary>
       

        public splashscreen form2;

        public form_main(splashscreen form2)
        {
            this.form2= form2;
        }
...
    }
}


der splashscreen
ausblenden C#-Quelltext
1:
2:
3:
4:
5:
6:
7:
8:
9:
10:
11:
12:
13:
14:
15:
16:
17:
18:
19:
using...

namespace GDISClient
{
    public partial class splashscreen : Form
    {
        /// <summary>
        /// Required designer variable.
        /// </summary>
        /// 
        public form_main form1;

        public splashscreen(form_main form1)
        {
            this.form1 = form1;
        }
...
    }
}


Ich kann zwar z.bsp. die Formen untereinander kommunizieren lassen, jedoch scheitert im moment die kommunikation aus einer klasse heraus, die dann die Form manipulieren soll.
Ja, ihr habt recht, das ist erst mal nicht die beste Lösung soll man nicht so machen. Ich brauch jedoch erst mal eine fertiges Konstrukt, an dem ich dann refactoren kann.
Step by Step sozusagen.

in der MainForm hab ichz.bsp.
ausblenden C#-Quelltext
1:
using (var splashscreen = new splashscreen(this))					


drin.

Dadurch kann ich von der MainForm, daten in splashscreen ändern.
Allerdings funktioniert die Using variante nicht in der MainKlasse, wo ich die Steuerung unterbringen will.
da liegt dann ein Konvertierungsproblem vor, da die klasse nicht in eine Form konvertiet werden kann, mittels using direktive.

Hat hier jemand eine Idee ?

P.S. Ich werde später dann einen "Broker" einbauen, der dann zwischen den forms vermittelt, aber im moment muß ich mich da erst rantasten.

Moderiert von user profile iconTh69: Code- durch C#-Tags ersetzt
Glowhollow Threadstarter
ontopic starontopic starontopic starontopic starontopic starontopic starontopic starhalf ontopic star
Beiträge: 77



BeitragVerfasst: Fr 05.04.19 09:41 
Nachtrag.

Verwende jetzt in den Hauptklassen, folgendes:

ausblenden Quelltext
1:
  form_main form_main = (form_main)Application.OpenForms["form_main"];					


Somit ist schon mal der Scope richtig gesetzt.

Mal sehen, ob ich das dann zum laufen kriege. Wenn ich mehr weiß, sag ich bescheid
Th69
ontopic starontopic starontopic starontopic starontopic starontopic starontopic starontopic star
Moderator
Beiträge: 4764
Erhaltene Danke: 1052

Win10
C#, C++ (VS 2017/19/22)
BeitragVerfasst: Fr 05.04.19 09:49 
Ich denke, mit deinem Ansatz jetzt kommst du so nicht weiter, sondern es wird immer komplizierter (zu viele Abhängigkeiten der Forms untereinander).

Zum einen:
Wenn du den "Splashscreen" zur Eingabe von Username und Passwort o.ä. nutzen willst, dann solltest du diese Form modal aufrufen, d.h.
ausblenden C#-Quelltext
1:
2:
3:
4:
5:
using (var splashscreen = new Splashscreen()) // Klassennamen sollten mit einem Großbuchstaben beginnen!
{
  DialogResult result = splashscreen.ShowDialog();
  // evtl. auf 'result' abfragen (OK, Cancel, ...)
}

z.B. vor Application.Run().

Und dann habe ich den Eindruck, daß dir noch nicht so ganz die Bedeutung der von dir verwendeten Konstruktor-Parameter klar ist, d.h. die Verwendung dieser als Referenzen.
Wenn du diese Referenz doch schon in deiner MainForm hast, warum erzeugst du dann eine neue Splashscreen-Instanz, anstatt die übergebene (bzw. als Klassenmember gespeicherte) zu verwenden?

Es ist auf jeden Fall aber zu vermeiden, daß untergeordnete Forms die übergeordneten Forms kennen.
Ich habe dazu einen (umfangreichen) Artikel geschrieben: Kommunikation von 2 Forms (speichere dir diesen am besten lokal komplett als HTML-Datei ab, da mein WebHoster bald diesen Zugang abstellt - sowie das Beispielprojekt als ZIP-Datei ganz unten).

PS: Zu deinem Nachtrag kann ich nur sagen, daß dieses die allerschlechteste aller Lösungen ist (es ist leider traurig, daß in einigen Sprachen der Zugriff auf globale Objekte so als Standard angesehen wird)!
Glowhollow Threadstarter
ontopic starontopic starontopic starontopic starontopic starontopic starontopic starhalf ontopic star
Beiträge: 77



BeitragVerfasst: Fr 05.04.19 10:38 
Hey Th69,

danke nochmal für die deutsche Erklärung (Site)!

Das mit der Referenz in der MainForm, hat sich glaube ich soweit erledigt, das war nur ein Versuch.

Und ja, es ist die allerschlechteste Lösung. Aber ich brauch erst mal ein funktionierendes Grundgerüst (nach der Konvertierung), das ich dann später umschreiben kann.

Wiegesagt, es ist nicht meine Absicht, das Ding einfach nur zu "adaptieren". Ziel ist es - das ganze ding dann später in ein MVC Pattern zu überführen.

Nur nutzt es mir nicht, das Ding komplett neu aufzusetzen, da ich das orginal nicht entwickelt habe, und mir da noch der Durchblick fehlt. Daher erst mal Adapation, dann refactoring.

P.S. Unser Systemintegrator hat das mal so "nebenbei" gemacht, und jetzt muß ich das Ding erst mal umschreiben. Da du aber selber wissen solltest, das gerade bei größeren Projekten (sind ca. 10k LOC) man diese Überführung schrittweise macht, muß ich erst mal ein grobes Konstrukt haben, um damit zu arbeiten.

Danke trotzdem für die Mühen, die du hier machst, das hilft mir wirklich. Danke.
Th69
ontopic starontopic starontopic starontopic starontopic starontopic starontopic starontopic star
Moderator
Beiträge: 4764
Erhaltene Danke: 1052

Win10
C#, C++ (VS 2017/19/22)
BeitragVerfasst: Fr 05.04.19 17:32 
Du solltest für das Grundgerüst am besten mal (auf Papier oder als Diagramm) alle benötigten Klassen (bzw. Forms) und deren Aufrufe bzw. Referenzen untereinander skizzieren.
Hilfreich ist dabei ein hierarchisches Modell (wie in meinem Artikel auch beschrieben), um eine Top-Down Sicht auf das gesamte Projekt zu erhalten (anstatt nur X Klassen, wo jede Klasse jede andere aufruft).

10k LOC ist aber eher ein mittleres Projekt. ;-)

Für größere Projekte mit vielen Klassen und Abhängigkeiten bietet sich Dependency Injection (bzw. Inversion of Control) an. Dafür gibt es eine Reihe von Libs: Liste von Dependency Injection Frameworks: .NET (damit du davon schon mal gehört hast und dich ein bißchen einlesen kannst ;- ).

PS: Bist du denn alleine an dem Projekt dran oder hast du noch einen erfahren(er)en Entwickler an deiner Seite?
Gerade bei einer Portierung kann es sein, daß man nicht alles 1:1 so umsetzen kann, wie im Original (insbesondere wenn noch Erfahrung in der Zielsprache/-framework fehlt).
Glowhollow Threadstarter
ontopic starontopic starontopic starontopic starontopic starontopic starontopic starhalf ontopic star
Beiträge: 77



BeitragVerfasst: Mo 08.04.19 14:33 
Th69,

ich weiß, ist nicht deine Aufgabe. Ich mach jetzt gleich das Grundgerüst un deren Abhängigkeiten als Diagramm fertig, Die Konvertierung von VB -> C# hab ich soweit durch. Würde das ganze dann als Bild fertig machen und hier hochladen, wenn das ok ist.

Das Diagramm muß ich eh erstellen, da ich später ja die Methoden/Funktionen erweitern muß (mit gettern und settern z.bsp.), dann hab ich da schon mal alles fertig um dann zu sehen was notwendig ist.

Würde gerne gerade was die Referenzierung untereinander anbetrifft, nochmal in Beschlag nehmen, da mein Ansatz mit

ausblenden Quelltext
1:
splashscreen splashscreen = (splashscreen)Application.OpenForms["splashscreen"];					


nicht so funktioniert wie ich mir das vorgestellt habe. Wiegesagt, ich mach jetzt die Abhängigkeiten, und würde gerne deine Meinung dazu hören. Und btw. Nein ich habe keinen erfahrenen Entwickler hier sitzen, bin der einzige :)
Glowhollow Threadstarter
ontopic starontopic starontopic starontopic starontopic starontopic starontopic starhalf ontopic star
Beiträge: 77



BeitragVerfasst: Mo 08.04.19 15:08 
So jetzt, habe die Abhängigkeiten mal grafisch dargestellt, hab dann aber die ganzen Methoden und Funktionen mal rausgelassen, da sie für die Übersicht, welche Forms mit welcher kommuniziert, unrelevant sind.

user defined image

mein ansatz war folgender z.bsp. (hier nur 1 beispiel).
ausblenden C#-Quelltext
1:
2:
3:
4:
5:
6:
splashscreen splashscreen = (splashscreen)Application.OpenForms["splashscreen"];
form_main form_main1 = (form_main)Application.OpenForms["form_main"];
pwchange pwchange1 = (pwchange)Application.OpenForms["pwchange"];
info_screen info_screen1 = (info_screen)Application.OpenForms["info_screen"];
fulltable fulltable = (fulltable)Application.OpenForms["fulltable"];
debugform debugform = (debugform)Application.OpenForms["debugform"];


Zwar werden im Editor die Referenzen richtig gesetzt, in der Anwendung jedoch klappt das nicht. Ich muß allerdings zugeben, das das in dir aufgeführte Beispiel, schon bei 2 Forms schon für Kopfschmerzen sorgt.

Wie bekomme ich jetzt ansatzweise hin, (ist ja nur für testzwecke), das die Felder und attribute von der mainform bzw. untereinander referenzieren können ?

Ich weiß, das das ganze nicht so trivial ist, und bräuchte hier evtl etwas Unterstützung. Und bitte nicht böse nehmen, kann etwas dauern, bis ich das verinnerlicht habe, aber wenns dann soweit ist, und ich das ganze verstanden habe, kann ich dann im späteren verlauf auch solche fragen beantworten.

Mag mir jemand dabei n bischen unter die arme greifen ?

Danke


P.S. Ich habe da noch eine Frage zu dem Punkt

ausblenden C#-Quelltext
1:
2:
3:
4:
using (var splashscreen = new Splashscreen()) // Klassennamen sollten mit einem Großbuchstaben beginnen!
{
  DialogResult result = splashscreen.ShowDialog(); 
}


Die Frage dazu ist. Angenommen, ich nutze in der Mainform, das using und kann damit auf splashscreen referenzieren. Das habe ich soweit verstanden, da ja ein neuer Splashscreen erzeugt wird, dann kann man über die Referenz auch Attribute ändern. Check.

Aber, was ist, wenn ich jetzt in den anderen Formen, ebenfalls referenzieren muß, und mit using (var info = new Info()) - die Referenz erzeuge. Was ist denn wenn ich jetzt in den einzelnen Forms, dann sozusagen mehrere "parallele" Referenzen habe. Ich meine mit new, instanziere ich neu. Habe ich dann nicht 2 oder mehr instanzen von ein und dem selben Objekt ? Führt das nicht zu referenzproblemen ?

Moderiert von user profile iconTh69: Code- durch C#-Tags ersetzt
Moderiert von user profile iconTh69: C#-Tags hinzugefügt
Th69
ontopic starontopic starontopic starontopic starontopic starontopic starontopic starontopic star
Moderator
Beiträge: 4764
Erhaltene Danke: 1052

Win10
C#, C++ (VS 2017/19/22)
BeitragVerfasst: Mo 08.04.19 17:35 
Lass auf jeden Fall den Zugriff mittels Application.OpenForms sein (denn dies funktioniert nur, wenn schon alle diese Forms erzeugt (und angezeigt) wurden).

Sollen die anderen Formulare denn alle gleichzeitig zur MainForm angezeigt (und bedienbar sein)? Oder doch eher modal?
Und wenn nicht-modal, dann ist noch die Frage, ob es davon immer nur genau 1 Formular gibt oder können mehrere davon gleichzeitig geöffnet werden?

Und zu deinem PS:
Mein Code mittels using und ShowDialog ist ja gerade für modale Formulare (Dialoge), welche erst nach dem Schließen wieder die Kontrolle an das aufrufende Formular abgeben, d.h. davon gibt es dann zeitgleich immer nur eine Instanz.
Nur bei nicht-modalen Formularen mußt du die Referenz (bzw. bei mehreren Formularen die Referenzliste) als Member der aufrufenden Klasse deklarieren.

Von den Namen her würde ich aber darauf tippen, daß diese Formulare modal aufgerufen werden sollen (nur bei Debug könnte es wohl auch nicht-modal angezeigt werden).

Du solltest auf jeden Fall immer nur eine Methode (in einer Klasse) haben, welche ein anderes Formular erzeugt und anzeigt.

Für den Fall, daß ein nicht-modales Unterformular nur genau 1x angezeigt wird, könnte die Methode etwa so aussehen:
ausblenden C#-Quelltext
1:
2:
3:
4:
5:
6:
7:
8:
9:
private NonModalForm _nonModalForm;

void ShowNonModalForm()
{
  if (_nonModalForm == null)
     _nonModalForm = new NonModalForm();

  _nonModalForm.Show(this);
}


PS: Die Pfeile in deinem Diagramm sollten nur in eine Richtung gehen (damit meine ich den Aufruf, nicht den Datenaustausch).
Glowhollow Threadstarter
ontopic starontopic starontopic starontopic starontopic starontopic starontopic starhalf ontopic star
Beiträge: 77



BeitragVerfasst: Di 09.04.19 14:09 
So, bin ein bischen weitergekommen. Allerdings krieg ich den Knoten in meinen Kopf noch nicht gelöst.

Im Moment habe ich folgendes. Ich habe eine MainKlasse (Program), die den Splashcreen initialisiert über Application.Run - splashcreen wird aufgerufen, wobei ich im aufruf eine neue Instanz von der MainForm erstelle und mit übergebe.

Program.cs enthält folgendes...
ausblenden C#-Quelltext
1:
2:
3:
4:
5:
6:
7:
8:
9:
10:
11:
12:
13:
14:
15:
16:
17:
18:
19:
20:
21:
namespace GDISClient
{
    public class Program : ApplicationContext
    {
        public Form_main mainForm = null;
       
        public static int startvar = 0;

        private static void Main(string[] args)
        {
            //Program context = new Program(new Form_main(new Debugform(), new Fulltable(), new Pwchange(), new Splashscreen(), new Info_screen()));
            var splash = new Splashscreen(new Form_main());
            Application.Run(splash);
        }
        public Program(Form_main mainForm)
        {
            this.mainForm = mainForm;
       
        }
    }
}


splashscreen enthält
ausblenden C#-Quelltext
1:
2:
3:
4:
5:
6:
7:
8:
9:
10:
11:
12:
13:
14:
15:
16:
17:
18:
19:
20:
21:
22:
23:
24:
25:
26:
27:
namespace GDISClient
{
    public partial class Splashscreen : Form
    {
        public Form_main mainForm;

        public Splashscreen(Form_main mainForm)
        {
            this.mainForm = mainForm;
        }

        private System.ComponentModel.IContainer components = null;

        protected override void Dispose(bool disposing)
        {
            if (disposing && (components != null))
            {
                components.Dispose();
            }
            base.Dispose(disposing);
        }

        private pwencode encoder = new pwencode();
        private dbcon mysqlcon = new dbcon(mainForm); // das hier funktioniert noch nicht, da der nicht statische verweis nicht auf die methode oder eigenschaft verweisen kann
        private useraccess UA = new useraccess();
    }
}

ich muß hier in dbcon - die mainForm, die über die program.cs mit erstellt worden ist mit übergeben. Ich weiß zwar im moment nicht, warum ich auf mainForm nicht zugreifen kann, bzw. verweisen, ist doch die variable public und im scope. Hab das kurzfristig mit static probiert, das würde gehen, jedoch kann ich dann nicht mehr debuggen um zu realisieren, warum ich eine NullReferenceException habe, obwohl die Form_main übergeben wird.

Hat hier jemand eine erklärung ?

dbcon ist eine eigenständige Klasse
ausblenden C#-Quelltext
1:
2:
3:
4:
5:
6:
7:
8:
9:
10:
11:
12:
13:
14:
15:
16:
17:
18:
19:
20:
21:
22:
23:
24:
25:
26:
27:
namespace GDISClient
{
    public class dbcon 
    {
        private MySqlConnection Con = new MySqlConnection();
        private MySqlConnection ConVJ = new MySqlConnection();
        private readonly string MySQLConnString = "...." //not of interest here
        public DataTable Table = new DataTable();

        public dbcon(Form_main mainForm)
        {
            this.mainForm = mainForm;
            Connectiontest();
        }

        public dbcon()
        {
           
            Connectiontest();
          
        }
        private Form_main mainForm;
   
   ...
   
   }
}


Moderiert von user profile iconTh69: Code- durch C#-Tags ersetzt
Moderiert von user profile iconTh69: C#-Tags hinzugefügt
Ralf Jansen
ontopic starontopic starontopic starontopic starontopic starontopic starontopic starhalf ontopic star
Beiträge: 4700
Erhaltene Danke: 991


VS2010 Pro, VS2012 Pro, VS2013 Pro, VS2015 Pro, Delphi 7 Pro
BeitragVerfasst: Di 09.04.19 20:21 
Zitat:
Hat hier jemand eine erklärung ?


Klassenvariablen werden vor dem Konstruktor initialisiert. Die Zuweisung zu mysqlcon sollte also auch im Konstruktor stattfinden.

Das ist aber eigentlich etwas was man mit einem simplen Debugging schnell raus gefunden hätte. Breakpoint auf den Konstruktor und einen auf die Klassenvariable. Beim ausführen wäre dir dann sofort aufgefallen das er bei der Klassenvariablen hält und erst dann im Konstruktor. Auch wenn es sicherlich viel zu lernen gibt um das umzusetzen was du willst ist gerade Debugging ein essentielles Werkzeug um auch zu verstehen was da passiert. Das solltest du dir frühzeitig aneignen. Das macht sich schnell bezahlt.

Es fühlt sich übrigens falsch an das eine Klasse die scheinbar zur Kapselung einer Datenbankverbindung dient eine Form kennen muss. Erst recht wenn die Instanz dieser Klasse zu einer Form gehört (Splashscreen) aber eine ganz andere kennen muss (Form_main).