Autor Beitrag
euglor
Hält's aus hier
Beiträge: 7



BeitragVerfasst: Fr 07.11.08 17:13 
Hallo Freunde.
Bin neu hier und fange ebenfalls gerade erst an mit C# und Windows Forms an und habe deswegen eine wahrscheinlich sehr banale Frage. Ich habe ein MainForm, aus welchem man über eine MenuStrip einen Dialog aufrufen kann. Jetzt möchte ich verschiedene Eigenschaften des MainForms aus diesem Dialog heraus ändern, wie z.B. die Hintergrundfarbe. Allerdings habe ich das Problem, dass ich nicht auf Variablen des MainForms zugreiffen kann... habe den code stark vereinfacht dargestellt.

Mein Hauptprogramm ist eigentlich standard:
ausblenden C#-Quelltext
1:
2:
3:
4:
5:
6:
7:
8:
9:
10:
11:
12:
13:
14:
15:
16:
namespace Taschenrechner
{
    static class Program
    {
        /// <summary>
        /// Der Haupteinstiegspunkt für die Anwendung.
        /// </summary>
        [STAThread]
        public static void Main()
        {
            Application.EnableVisualStyles();
            Application.SetCompatibleTextRenderingDefault(false);
            Application.Run(new MainForm());
        }
    }
}


Dann habe ich mein MainForm:

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:
namespace Taschenrechner
{
    public partial class MainForm : Form
    {
        EinstDlg oEinstDlg = new EinstDlg();

        int R = 155;

        public MainForm()
        {
            InitializeComponent();

            //Setzen der Eigenschaften des Hauptfensters
            this.BackColor = System.Drawing.Color.FromArgb(R, 155155);
        }
        
        private void einstellungenToolStripMenuItem_Click(object sender, EventArgs e)
        {
            oEinstDlg.ShowDialog(this);
        }


    }
}


Von meinem Dialog aus möchte ich dann z.B. durch eine TrackBar den Rot-Kanal der Hintergrundfarbe des MainForms manipulieren. Ich habe keine Probleme damit dies für den Dialog zu tun, in dem sich die Trackbar befindet, aber bekomme es nicht auf das MainForm angewandt.

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:
namespace Taschenrechner
{
    public partial class EinstDlg : Form
    {

        public EinstDlg()
        {
            InitializeComponent();
            ...
        }
           ...
       
        private void trackBar1_ValueChanged(object sender, EventArgs e)
        {
            //Für diesen Dialog geht es
            //[b]this[/b].BackColor = System.Drawing.Color.FromArgb(this.trackBar3.Value, 155, 155);

            //Diese Ansätze funktionieren nicht...
            MainForm.R = ...
            //oder
            MainForm.BackColor...
        }

Beim Versuch die Variable anzusprechen gibts die Fehlermeldung, dass der Name "R" nicht im aktuellen Kontekt vorhanden ist... was mache ich falsch? Wieso kann ich nicht auf das in der Main erzeugte Objekt MainForm in der Art zugreifen?
Vielen Dank für Eure Hilfe!

greetz
Kha
ontopic starontopic starontopic starontopic starontopic starontopic starontopic starhalf ontopic star
Beiträge: 3803
Erhaltene Danke: 176

Arch Linux
Python, C, C++ (vim)
BeitragVerfasst: Fr 07.11.08 17:40 
user profile iconeuglor hat folgendes geschrieben Zum zitierten Posting springen:
Wieso kann ich nicht auf das in der Main erzeugte Objekt MainForm in der Art zugreifen?
Das ist der springende Punkt: Du hast in deinem Dialog keine Referenz auf dieses Objekt, es wurde in Main ja nicht einmal in einer Variablen gespeichert. Du musst dem Dialog also this mitgeben, z.B. als Konstruktor-Parameter, damit er überhaupt weiß, welche Form er ändern soll.

Wobei es doch meistens so gelöst wird, dass Änderungen erst bei Schließen des Dialogs übernommen werden. Dazu müsstest du also der Dialog die Farbe nach außen weitergeben können (=> public Property), nach dem ShowDialog in der MainForm kannst du dann diesen Wert für BackColor übernehmen. Mit dieser Lösung hast du auch den Dialog von MainForm entkuppelt, was nie schlecht ist.

_________________
>λ=
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: Fr 07.11.08 17:50 
Hallo und :welcome:

das sind Grundbedingungen der OOP: Ein Objekt (d.h. eine konkrete Instanz einer Klasse) darf nur auf abhängige Objekte Zugriff haben, aber nicht auf übergeordnete. Das MainForm darf etwas mit dem Einstellungsdialog machen, weil das MainForm den Dialog erzeugt hat, aber nicht umgekehrt. Zugriffe sollten über Eigenschaften (Properties) gehen; deshalb sind beispielsweise Dialog.Controls als private deklariert und nicht als public.

Wenn tatsächlich einmal eine solche "Rückkopplung" erforderlich ist, muss das über Ereignisse und Delegates laufen. Eine gute Beschreibung dieser Probleme ist unter [FAQ] Kommunikation von 2 Forms und den dort genannten Links zu finden.

Du hast zusätzlich noch den Fehler gemacht, dass Du vom Dialog aus den Namen der Klasse benutzt hast, aber nicht den Namen einer Instanz; so etwas ginge (wenn es überhaupt möglich wäre - siehe oben) nur mit static-Membern.

Es scheint, dass Du Dich intensiv um Grundlagen bemühen solltest, z.B. durch OpenBook VC#.

Viel Erfolg! Jürgen
Greenberet
ontopic starontopic starontopic starontopic starontopic starontopic starofftopic starofftopic star
Beiträge: 339
Erhaltene Danke: 20

Win 10
C# (VS 2012), C++ (VS 2012/GCC), PAWN(Notepad++), Java(NetBeans)
BeitragVerfasst: Fr 07.11.08 22:16 
user profile iconKha hat folgendes geschrieben Zum zitierten Posting springen:
user profile iconeuglor hat folgendes geschrieben Zum zitierten Posting springen:
Wieso kann ich nicht auf das in der Main erzeugte Objekt MainForm in der Art zugreifen?
Das ist der springende Punkt: Du hast in deinem Dialog keine Referenz auf dieses Objekt, es wurde in Main ja nicht einmal in einer Variablen gespeichert. Du musst dem Dialog also this mitgeben, z.B. als Konstruktor-Parameter, damit er überhaupt weiß, welche Form er ändern soll.

Tut er doch ;)
beim aufruf von ShowDialog übergibt er "this" als parent Window, im Prinzip müsste er nur das Parent Property ansprechen und dessen Hintergrundfarbe etc. setzen.

Aber abgesehen davon muss ich meinen 2 vorpostern rechtgeben =)

-
Green
euglor Threadstarter
Hält's aus hier
Beiträge: 7



BeitragVerfasst: Fr 07.11.08 22:54 
Hallo Freunde!

Erstmal danke für die zahlreichen und vor allem schnellen Antworten. Natürlich habt ihr recht, dass ich noch so einiges lernen muss, aber irgendwo muss man ja mal anfangen zu fragen, wenn man selbst nicht weiter kommt. Und beim Bearbeiten spezifischer Probleme lernt man doch am besten. :)
Genau so wie von Greenberet beschrieben wollte ich das ganze eigentlich vom Prinzip her angehen... Ich habe auch gleich mal versucht mit
ausblenden C#-Quelltext
1:
ParentForm.BackColor = System.Drawing.Color....					

die Farbe zu ändern. Visual Studio 2008 gibt mir auch schön brav die Vorlagen dazu, allerdings bekomme ich eine System.NullReferenceException - habe auch schon diverse Foren durch, aber das Problem noch nicht beheben können. Ich muss ja der Property ein Objekt zuweisen mit
ausblenden C#-Quelltext
1:
2:
MainForm oMF = new MainForm();
oMF.BackColor. ....

aber das haut auch nicht hin. Ich bin mir auch nicht so ganz im klaren wo genau ich das dann machen muss. Bei allen meinen anderen Objekt-Instanziierungen funktioniert das wunderbar. Vielleicht hat noch jemand einen Tip für mich, ich wäre sehr dankbar. :P

Viele Grüße!
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: Sa 08.11.08 12:45 
Hallo,

ParentForm ist falsch:
Zitat:
Ruft das Formular ab, dem das Containersteuerelement zugewiesen ist.

Damit bekommst Du z.B. für ein Panel das Formular, in dem das Panel liegt. Du brauchst die Form.Owner-Eigenschaft:
Zitat:
Mit dieser Version der ShowDialog-Methode können Sie ein bestimmtes Formular oder Steuerelement angeben, das Besitzer des angezeigten Dialogfelds wird.

Wenn Du im Dialog den Owner abfragst bzw. verwendest, bekommst Du das MainForm, aber vom Typ Form und nicht vom Typ MainForm. Notfalls kann es also so funktionieren:
ausblenden C#-Quelltext
1:
this.Owner.BackColor = System.Drawing.Color....					

"this" habe ich nur zur Verdeutlichung geschrieben; das kann (fast) immer weggelassen werden.

Dein zweiter Versuch ist abwegig: Damit erzeugst Du ein neues MainForm, greifst aber keinesfalls auf das vorhandene zu. ("new" für ein Formular in einem EventHandler macht eigentlich nur dann Sinn, wenn anschließend das neue Formular angezeigt werden soll; in [fast] allen anderen Fällen verweist ein solcher Versuch auf ein völlig undurchdachtes Vorgehen.)

Aber das oben Gesagte soll nur das Vorgehen verdeutlichen. Greife besser per Delegate auf das Hauptformular zu.

Jürgen
euglor Threadstarter
Hält's aus hier
Beiträge: 7



BeitragVerfasst: Sa 08.11.08 21:56 
Hallo Leute. Ja vielen Dank für die Tips. Ich habe es jetzt versucht mit Delegates zu realisieren. Bis auf eine Kleinigkeit gehts auch schon.
Hab jetzt in meinem Dialog das Delegate eingefügt
ausblenden C#-Quelltext
1:
2:
3:
4:
5:
6:
7:
8:
9:
10:
11:
public partial class EinstDlg : Form
    {
        public delegate void GuardCallback(int R, int G, int B);
        public GuardCallback cb;
        
        public EinstDlg(GuardCallback guard)
        {
            cb = guard;

            [...]
        }

und in der Methode wo ich die entsprechenden Variablen, die ich an das MainForm übergeben möchte setze ich
ausblenden C#-Quelltext
1:
2:
if(null != cb)
   cb(wert1, wert2, wert3);

Im MainForm melde ich, bevor ich den Dialog öffne, den Beobachter an mit
ausblenden C#-Quelltext
1:
2:
3:
4:
            EinstDlg.GuardCallback g = new EinstDlg.GuardCallback(Guard.SupervisingMethod);
            EinstDlg oEinstDlg = new EinstDlg(g);

            oEinstDlg.ShowDialog(this);

und in meiner Klasse Guard habe ich dann letztendlich die Überwachungsfunktion
ausblenden C#-Quelltext
1:
2:
3:
4:
5:
6:
7:
8:
9:
    class Guard : MainForm
    {
        public static void SupervisingMethod(int R, int G, int B)
        {
            //string raus = "1. : " + R.ToString() + "\n2. : " + G.ToString() + "\n3. : " + B.ToString();
            //MessageBox.Show(raus);
        }

    }

Wie ihr seht, habe ich versucht mir die aktuellen Werte aus dem Dialog ausgeben zu lassen. Das funktioniert super. Allerdings bin ich immer noch an meinen Grundproblem: und zwar ist es mir nicht möglich, die Properties des MainForm zu ändern... ich will ja dem MainForm.BackColor einfach nur die RGB Werte des Dialogs zuweisen. Macht auch keinen Unterschied, ob ich nun die SupervisingMethod innerhalb der MainForm Klasse habe oder in der Guard (ist mir lieber weil übersichtlicher). Ich hätte nun gedacht, dass ich einfach mit der Selbstreferenzierung this. ... die Eigenschaften setzen kann. Wo ist mein Denkfehler? Wäre nett, wenn ihr mir da kurz aushelfen könntet, denn eigentlich stehe ich jetzt vor genau dem gleichen Problem wie ganz am Anfang. :P

vielen Dank und Grüße!
eugler


Zuletzt bearbeitet von euglor am Sa 08.11.08 22:41, insgesamt 1-mal bearbeitet
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: Sa 08.11.08 22:14 
Ich muss heute noch etwas erledigen, deshalb kann ich Deinen Versuch nicht begutachten. Ich habe aber inzwischen doch die Frage, ob Du der gleiche Fragesteller bist wie brown78 in Eine Form für mehrere Zwecke? Das Verfahren unterscheidet sich, aber die Fragestellung kommt mir ziemlich ähnlich vor. Jürgen
euglor Threadstarter
Hält's aus hier
Beiträge: 7



BeitragVerfasst: Sa 08.11.08 22:21 
Nein. Das ist mein 1. Posting zu c# und Windows Forms. Hab mir grad den Beitrag durchgelesen, aber weiter gebracht hat es mich leider auch nicht. Aber es ist ja auch nicht so abwegig, dass man aus einem Einstellungs-Dialog heraus Eigenschaften des Hauptfensters ändern möchte. Die Farbe habe ich nur als Beispiel gewählt um die Grundfunktionalität herzustellen. Denke wenn das Prinzip steht, sollte es einfach sein, auch die interessanteren Eigenschaften, wie z.B. Schriftgröße oder das Ein- und Ausschalten von Steuerelementen zu regeln. :D

Gruss
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: So 09.11.08 12:55 
So, jetzt habe ich Zeit und den Kopf frei.

user profile iconeuglor hat folgendes geschrieben Zum zitierten Posting springen:
... ich will ja dem MainForm.BackColor einfach nur die RGB Werte des Dialogs zuweisen. Macht auch keinen Unterschied, ob ich nun die SupervisingMethod innerhalb der MainForm Klasse habe oder in der Guard (ist mir lieber weil übersichtlicher).

Nein, das macht eben doch etwas aus: Du willst eine Änderung in der MainForm machen; also brauchst Du einen DelegateHandler im MainForm. Das ist auch sinnvoll, weil Du in der GUI etwas ändern willst. Du musst also die Methode, die im MainForm die Farben setzt, auch dort definieren:
ausblenden C#-Quelltext
1:
2:
3:
4:
5:
6:
7:
8:
//  im MainForm
private void SetNewColor(int R, int G, int B)
{
   this.BackColor = Color.FromArgb(R, R, B);
}

//  diese Methode an den Dialog übergeben
           EinstDlg oEinstDlg = new EinstDlg(SetNewColor);

Alles andere kann (glaube ich) so bleiben.

Allerdings sehe ich noch einige "Kleinigkeiten", die bereinigt werden sollten:
  • public ist überall, wo es möglich ist, durch private zu ersetzen (ich sehe es jedenfalls bei der Variablen cb).
  • Eine static-Methode macht etwas unabhängig von einer bestimmten Instanz. Du willst aber die aktuelle MainForm benutzen; also darf SupervisingMethod nicht static sein.
  • Wieso ist die Klasse Guard eigentlich von MainForm abgeleitet? Das macht aus meiner Sicht überhaupt keinen Sinn.
  • Lies einmal die Richtlinien für die Benennung durch. Diese sind keine "Bibel"; es ist aber sinnvoll, sich danach zu richten, damit vor allem bei Groß- und Kleinbuchstaben der Geltungsbereich einer Variablen schnell erkannt werden kann.
  • Ich empfehle außerdem, gemischte deutsche und englische Begriffe sowie Abkürzungen bei Bezeichnern zu vermeiden. Beispiel: EinstDlg >> EinstellungenDlg >> EinstellungenDialog >> OptionsDialog (meinetwegen auch OptionsDlg; Dlg ist eine gängige Abkürzung). Spätestens wenn die IDE EventHandler produziert, gibt es schlimmsten denglischen Mischmasch wie EinstDlg_Load - dann lieber durchgehend Englisch (wie das ganze NET Framework).

Gruß Jürgen
euglor Threadstarter
Hält's aus hier
Beiträge: 7



BeitragVerfasst: So 09.11.08 13:22 
Hallo Jürgen!

Ja Wahnsinn, es funktioniert. Super. Das entscheidende Problem war tatsächlich die Tatsache, dass die Methode SupervisingMethod(int R, int G, int B) static gesetzt war. Dadurch konnte ich die Selbtreferenzierung nicht nutzen. Ansonsten habe ich alles so gelassen. Ich habe mir den Code für diese Methode automatisch von VS2008 generieren lassen - das kommt davon! Selber schreiben ist immer besser.
Zu den restlichen Anmerkungen: Du hast natürlich Recht! Der Code ist sehr unsauber, aber ich tendieren immer irgendwie dazu, wenn ich "nur probiere" wie etwas funktioniert. Aber ich seh ein, dass ich das noch ändern sollte, wenn ich es poste. Zu public/private: Ich mach meistens erst alles public und ändere das dann im nachhinein. Die Klasse Guard von Form abzuleiten war ein Unfall... :angel:

Nochmal vielen Dank für Deine bzw. Eure Hilfe!

Auf bald ;)