Entwickler-Ecke

WinForms - Form von Dialog aus ändern (z.B. BackColor)


euglor - Fr 07.11.08 17:13
Titel: Form von Dialog aus ändern (z.B. BackColor)
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:

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:


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.


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 - Fr 07.11.08 17:40
Titel: Re: Form von Dialog aus ändern (z.B. BackColor)
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 - 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 [http://www.mycsharp.de/wbb2/thread.php?threadid=5960] 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# [http://openbook.galileocomputing.de/visual_csharp/].

Viel Erfolg! Jürgen


Greenberet - Fr 07.11.08 22:16
Titel: Re: Form von Dialog aus ändern (z.B. BackColor)
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 - 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

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

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 - 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:

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 - 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

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

C#-Quelltext
1:
2:
if(null != cb)
   cb(wert1, wert2, wert3);

Im MainForm melde ich, bevor ich den Dialog öffne, den Beobachter an mit

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

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


JüTho - 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? [http://entwickler-forum.de/showthread.php?t=52056] Das Verfahren unterscheidet sich, aber die Fragestellung kommt mir ziemlich ähnlich vor. Jürgen


euglor - 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 - 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:

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:

Gruß Jürgen


euglor - 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 ;)