Autor Beitrag
Ares
ontopic starontopic starontopic starontopic starontopic starontopic starontopic starontopic star
Beiträge: 128



BeitragVerfasst: Mi 14.01.09 15:17 
Hallo!

Ich habe bislang nur mit Delphi gearbeitet und mache gerade meine ersten Schritte in C#. Nun stehe ich allerdings schon beim Zugriff auf das Form-Objekt auf dem Schlau:

Ich habe ein neues Windows-Forms Projekt erstellt und damit folgenden Code erhalten:

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:
namespace TestProgramm {
    static class TestProgramm {
        /// <summary>
        /// Der Haupteinstiegspunkt für die Anwendung.
        /// </summary>
        [STAThread]
        static void Main() {
            Application.EnableVisualStyles();
            Application.SetCompatibleTextRenderingDefault(false);
            Application.Run(new Form1());
        }

        // Selbst erstellte Methode
        public void MyMethod() {
           MachWasMitDemForm(...);
        }
    }


    // Selbst erstellte Klasse
    public class MyClass {
        public void MyClass() {
           MachWasMitDemForm(...);         
        }
    }
}


Frage 1:
Wie kann ich in der Methode MachWasMitDemForm() auf das Formobjekt zugreifen? Das Objekt wurde ja nur mit "new Form1()" erstellt, ich habe also keine Variable die auf das Objekt zeigt wie das bei "Form1 myForm = new Form1()" wäre...

Frage 2:
Wie kann ich aus einer anderen Klasse aus auf das Form zugreifen? In Delphi wird zu einem Formular ja immer eine globale Variable erstellt, so das der Zugriff auf ein Form kein Problem ist. In C# scheint es das nicht zu geben, wie kann ich dort also aus einer anderen Klasse auf ein Form-Objekt zugreifen? Muss ich der Klasse immer eine Referenz auf das Form übergeben oder gibt es hierfür eine andere Lösung?

Besten Dank
Ares
AdrianK
ontopic starontopic starontopic starontopic starontopic starontopic starofftopic starofftopic star
Beiträge: 56

Kubuntu 9.04 Jaunty
Mono 2.4 + MonoDevelop 2.0; Qt Creator
BeitragVerfasst: Mi 14.01.09 16:35 
Deinen Code würde ich nicht in die program.cs sondern in die form1.cs machen, da ist das dann auch kein Problem...
@Edit: Gibts auch ne schöne MSDN-Webcast-Serie dazu: www.microsoft.com/ge...y.aspx?id=1032362210
jaenicke
ontopic starontopic starontopic starontopic starontopic starontopic starontopic starofftopic star
Beiträge: 19315
Erhaltene Danke: 1747

W11 x64 (Chrome, Edge)
Delphi 11 Pro, Oxygene, C# (VS 2022), JS/HTML, Java (NB), PHP, Lazarus
BeitragVerfasst: Mi 14.01.09 16:40 
Es gab ähnliche Fragen in letzter Zeit immer wieder:
www.c-sharp-forum.de...ach+Form1_89094.html
www.c-sharp-forum.de...Variablen_89215.html
user profile iconjaenicke hat folgendes geschrieben Zum zitierten Posting springen:
Die Frage zu der Kommunikation zwischen zwei Formularen gab es immer wieder:
www.c-sharp-forum.de/viewtopic.php?t=88171
www.c-sharp-forum.de...ewtopic.php?p=536142
Eine Antwort gibt u.a. dieser FAQ-Eintrag:
www.mycsharp.de/wbb2...ead.php?threadid=488

usw.

Ich nehme einmal an, dass dir das bereits hilft. ;-)
JüTho
ontopic starontopic starontopic starontopic starontopic starontopic starontopic starhalf ontopic star
Beiträge: 2021
Erhaltene Danke: 6

Win XP Prof
C# 2.0 (#D für NET 2.0, dazu Firebird); früher Delphi 5 und Delphi 2005 Pro
BeitragVerfasst: Mi 14.01.09 16:57 
Hallo,

Du musst in der Tat etwas umdenken: Delphi ist nur "teilweise" objektorientiert, aber NET und C# vollständig. Das bedeutet, dass irgendeine Klasse von Details einer anderen Klasse nichts, aber auch gar nichts weiß. Die Kommunikation zwischen zwei Klassen findet nur über dafür vorbereitete Schnittstellen (das sind Schnittstellen im Sinne der OOP, aber kein interface von C#) statt. Die Aufgabe darf deshalb nicht lauten: MachWasMitForm1, sondern Form1.SollWasTun. Außerdem muss die Maßnahme "Mach was" immer dort stehen, wo sie von der Sachlogik her hingehört. Aufgaben, die zu einem Formular gehören, sollten innerhalb des Formulars deklariert und implementiert werden.

In Deiner Situation hast Du drei Klassen: TestProgramm, Form1, MyClass. TestProgramm steuert den Programmablauf. (Standardmäßig heißt diese Klasse Program.) Zusätzliche Methoden wie MyMethod haben dort nur insoweit etwas zu suchen, wie es mit dem Programmablauf zusammenhängt. In der Praxis kann ich nur folgende Situation für sinnvoll halten:
ausblenden C#-Quelltext
1:
2:
3:
4:
5:
6:
7:
8:
9:
10:
11:
12:
13:
14:
15:
16:
17:
18:
19:
static class TestProgramm {
    [STAThread]
    static void Main() {
        Application.EnableVisualStyles();
        Application.SetCompatibleTextRenderingDefault(false);
        //  Abfrage nach Login-Name
        string username = String.Empty;
        using(LoginForm login = new LoginForm()) {
            if (login.ShowDialog() == DialogResult.OK)
                username = login.Username;
        }
        if (! String.IsNullOrEmpty(username)) {
            MainForm main = new MainForm();
            //  mach was mit dem Formular
            main.Init(username);
            Application.Run(main);
        }
    }
}

Die Frage 1 kann also etwa so beantwortet werden: Wenn es eine Notwendigkeit gibt, kannst Du Dir mit einer Variablen den Zugriff auf das Formular verschaffen. Aber Du darfst damit nur auf public-Member zugreifen, also auf Eigenschaften, die die Kommunikation über die Schnittstelle steuern, und auf Methoden, die dafür vorgesehen sind.

Etwas schwieriger ist Frage 2 zu beantworten, weil es keine allgemeingültigen Situationen gibt. Es hängt z.B. davon ab, ob eine Instanz von MyClass vom Formular erzeugt wird oder umgekehrt und welchen Einfluss die Instanzen aufeinander haben sollen. Vereinfacht gesagt: Die erzeugende Klasse darf die erzeugte Klasse kennen, aber nicht umgekehrt. Auch für diese "Kenntnis" gilt die Beschränkung auf die Schnittstelle.

Um es noch etwas komplizierter zu machen: Wenn die erzeugte Klasse etwas in der erzeugenden Klasse erledigen soll, kann ein Delegate benutzt werden; das entspricht in etwa einem Methodenzeiger. Wenn ein Objekt (z.B. eine Klasse, die einem Datenmodul entspricht) allen Formularen in exakt der gleichen Situation bekannt sein soll, kann es als Singleton eingebaut werden.

Weitere Erläuterungen zu Deinen Verständnisproblemen findest Du z.B. unter FAQ Kommunikation zwischen 2 Forms (wie von Sebastian erwähnt) und den dort genannten Verweisen.

Viel Erfolg! Jürgen

Weitere einführende Literatur:
OpenBook Visual C#
OpenBook C#
OpenBook OOP
Ares Threadstarter
ontopic starontopic starontopic starontopic starontopic starontopic starontopic starontopic star
Beiträge: 128



BeitragVerfasst: Mi 14.01.09 18:17 
Vielen Dank für eure Antworten. Diese und die Verweise auf die anderen Quellen waren schon einmal sehr hilfreich.

Ein paar Verständnisprobleme habe ich trotzdem noch:

Frage 1:
Habe ich es richtig verstanden, dass in der "Hauptklasse" Programm und der Methode static void Main() {...} im Allgemeinen nichts anderes gemacht werden soll als das Programm zu starten? Außer dem automatisch erzeugten Code sollte man hier nur was einfügen wenn man einen wirklich guten Grund dafür hat. Alles weitere (im Allgemeinen) sollte lieber aus der Form-Klasse gestartet / gesteuert werden. Habe ich das richtig verstanden?

Frage 2:
Objekt A erzeugt Objekt B. In diesem Fall sollte Objekt B prinzipiell nichts von Objekt A wissen und folglich auch nicht auf dieses zugreifen. Muss B an A dennoch unbedingt Änderungen vornehmen sollte man das über über Events oder Delegates regeln. Richtig verstanden?

Solche Fälle habe ich bislang immer so geregelt, dass Objekt A in Objekt B als Parent bekannt ist:
ausblenden C#-Quelltext
1:
2:
3:
4:
5:
// In Objekt A:
ObjektB objB = new ObjektB(this);

// In Objekt B:
Parent.MachWas(...);


Was spricht gegen ein solches vorgehen bzw. was ist an Delegates und Events als an einem solchen Parent-Verweis?

Besten Dank
Ares
JüTho
ontopic starontopic starontopic starontopic starontopic starontopic starontopic starhalf ontopic star
Beiträge: 2021
Erhaltene Danke: 6

Win XP Prof
C# 2.0 (#D für NET 2.0, dazu Firebird); früher Delphi 5 und Delphi 2005 Pro
BeitragVerfasst: Mi 14.01.09 18:23 
user profile iconAres hat folgendes geschrieben Zum zitierten Posting springen:
Frage 1:
Habe ich es richtig verstanden, dass in der "Hauptklasse" Programm und der Methode static void Main() {...} im Allgemeinen nichts anderes gemacht werden soll als das Programm zu starten? Außer dem automatisch erzeugten Code sollte man hier nur was einfügen wenn man einen wirklich guten Grund dafür hat. Alles weitere (im Allgemeinen) sollte lieber aus der Form-Klasse gestartet / gesteuert werden. Habe ich das richtig verstanden?

Ja.

user profile iconAres hat folgendes geschrieben Zum zitierten Posting springen:
Frage 2:
Objekt A erzeugt Objekt B. In diesem Fall sollte Objekt B prinzipiell nichts von Objekt A wissen und folglich auch nicht auf dieses zugreifen. Muss B an A dennoch unbedingt Änderungen vornehmen sollte man das über über Events oder Delegates regeln. Richtig verstanden?

Ja.

user profile iconAres hat folgendes geschrieben Zum zitierten Posting springen:
Solche Fälle habe ich bislang immer so geregelt, dass Objekt A in Objekt B als Parent bekannt ist:
ausblenden C#-Quelltext
1:
2:
3:
4:
5:
// In Objekt A:
ObjektB objB = new ObjektB(this);

// In Objekt B:
Parent.MachWas(...);


Was spricht gegen ein solches vorgehen ...

Es gibt Situationen, in denen das Verfahren über Parent sinnvoll ist. Ich würde das aber möglichst vermeiden.

Gruß Jürgen
Ares Threadstarter
ontopic starontopic starontopic starontopic starontopic starontopic starontopic starontopic star
Beiträge: 128



BeitragVerfasst: Mi 14.01.09 18:27 
user profile iconJüTho hat folgendes geschrieben Zum zitierten Posting springen:

Es gibt Situationen, in denen das Verfahren über Parent sinnvoll ist. Ich würde das aber möglichst vermeiden.


Aus Gründen des Geschmacks oder gibt es hierfür auch ganz praktische Gründe?
Christian S.
ontopic starontopic starontopic starontopic starontopic starontopic starhalf ontopic starofftopic star
Beiträge: 20451
Erhaltene Danke: 2264

Win 10
C# (VS 2019)
BeitragVerfasst: Mi 14.01.09 18:32 
Aus Gründen einer korrekten Kapselung.

Mit Deiner Methode ist Objekt B dafür verantwortlich, dass in Objekt A etwas passiert. Wenn Du es über ein Event machst, ist alleine Objekt A dafür verantwortlich, auf dieses Event zu reagieren. Das ist zum einen eine saubere Trennung (B muss nichts über die Implementationsdetails von A wissen), zum anderen hat es auch den praktischen Vorteil, dass Du bei einer Änderung in A nicht auch B ändern musst.

_________________
Zwei Worte werden Dir im Leben viele Türen öffnen - "ziehen" und "drücken".
Hobbyprg
Hält's aus hier
Beiträge: 7


VS C# 2008
BeitragVerfasst: Fr 30.01.09 22:44 
user profile iconAdrianK hat folgendes geschrieben Zum zitierten Posting springen:
Deinen Code würde ich nicht in die program.cs sondern in die form1.cs machen, da ist das dann auch kein Problem...
@Edit: Gibts auch ne schöne MSDN-Webcast-Serie dazu: www.microsoft.com/ge...y.aspx?id=1032362210


Schöner Link (kannte ich noch gar nicht) :zustimm:
Den C# Grundlagen habe ich mir dann gleich auch noch
mal zu Gemüte geführt. 8)