Laden...

Wie kann ich neben Variablenwerten auch den DialogResult zwischen Forms richtig übergeben?

Erstellt von Delfis vor 6 Jahren Letzter Beitrag vor 6 Jahren 3.666 Views
D
Delfis Themenstarter:in
24 Beiträge seit 2017
vor 6 Jahren
Wie kann ich neben Variablenwerten auch den DialogResult zwischen Forms richtig übergeben?

Hallo liebe C#-Nutzer!

Und schon kommt die nächste Frage:

Bei der Rückkehr von einer aufgerufenen Form werden die Variablenwerte zwar korrekt übergeben, nicht aber das Ergebnis des DialogResults. In der Form2 ist er als "OK" definiert und mit diesem Wert wird die Form2 auch verlassen. In der aufrufenden Form1 erscheint der Wert aber als "NONE", deshalb werden die Variablenwerte nicht in die Textboxen geschrieben. Es ändert sich nichts, wenn ich in der Form2 "Close" lösche. Wo liegt der Fehler?


Ende des Programms in Form2:

        private void button1_Click(object sender, EventArgs e)
        {
            X_min = Convert.ToDecimal(Xmin_box.Text);
            X_max= Convert.ToDecimal(Xmax_box.Text);
            Close();
        }

Rücksprung in aufrufende Form1:

        private void AchsenkalibrierungToolStripMenuItem_Click(object sender, EventArgs e)
        {
            Form2 f2 = new Form2();
            if (f2.ShowDialog() == DialogResult.OK)
            {
                textBox1.Text = f2.Kal;

                textBox1.Text = Convert.ToString(f2.X_min);
                textBox3.Text = Convert.ToString(f2.X_max);
            }
        }

Danke für Eure Hilfe!

16.806 Beiträge seit 2008
vor 6 Jahren

Es ist nirgends zu erkennen, dass Du das DialogResult auch setzt.
None spricht dafür, dass Du es nicht setzt.

D
Delfis Themenstarter:in
24 Beiträge seit 2017
vor 6 Jahren

Hallo Abt,

der DialogResult wird doch dadurch auf "OK" gesetzt, dass ich die Form2 mit dem Drücken des Buttons verlasse, so zeigt es auch der Debugger an. Oder wie muss ich hier den DialogResult noch extra setzen?

H
523 Beiträge seit 2008
vor 6 Jahren

Du musst das DialogResult in der Form setzen von der Du das OK erwartest:


    public partial class Form1 : Form
    {
        public Form1()
        {
            InitializeComponent();
        }

        private void button1_Click(object sender, EventArgs e)
        {
            Form2 form = new Form2();
            DialogResult result = form.ShowDialog();
            MessageBox.Show(result.ToString());
        }
    }


    public partial class Form2 : Form
    {
        public Form2()
        {
            InitializeComponent();
        }

        private void button1_Click(object sender, EventArgs e)
        {
            this.DialogResult = DialogResult.OK;
            this.Close();
        }
    }

D
Delfis Themenstarter:in
24 Beiträge seit 2017
vor 6 Jahren

Hallo hypersurf,

Danke für den Tipp, ich habe die Änderungen vorgenommen, nun wird tatsächlich auch "OK" übertragen. Die vorher programmierte Version hatte ich in einem youtube-video gefunden, bei dem ein Text aus einer zweiten in die aufrufende Form übertragen wurde.
Trotz allem werden die Textfelder nicht gefüllt. Beim Debuggen werden mir die richtigen Textfeldeinträge gezeigt, kommen aber nicht zur Darstellung. Woran liegt das? Hier nochmals der nun geänderte Code:



        private void AchsenkalibrierungToolStripMenuItem_Click(object sender, EventArgs e)
        {
            Form2 f2 = new Form2();
            DialogResult result = f2.ShowDialog();

            if (result == DialogResult.OK)
            {
                textBox1.Text = f2.Kal;

                textBox2.Text = Convert.ToString(f2.X_min);
                textBox3.Text = Convert.ToString(f2.X_max);
            }

            MessageBox.Show(result.ToString());
        }
    }

Danke!

16.806 Beiträge seit 2008
vor 6 Jahren

der DialogResult wird doch dadurch auf "OK" gesetzt, dass ich die Form2 mit dem Drücken des Buttons verlasse

Ich glaube nicht, dass der Debugger was anderes macht, als Dein Code zeigt.
Das wäre der erste Debugger, der das tut.

D
Delfis Themenstarter:in
24 Beiträge seit 2017
vor 6 Jahren

Nächster Versuch: Ich habe die Textboxeinträge in die Messagebox kopiert und darin werden alle Variablenwerte aus der Form2 korrekt angezeigt. Es bleibt die Frage, warum das nicht in den Textfeldern möglich ist :

 
      private void AchsenkalibrierungToolStripMenuItem_Click(object sender, EventArgs e)
        {
            Form2 f2 = new Form2();
            DialogResult result = f2.ShowDialog();

            if (result == DialogResult.OK)
            {
                //textBox1.Text = "Test";
                //textBox1.Text = f2.Kal;
                MessageBox.Show(f2.Kal + " " + Convert.ToString(f2.X_min) + " " + Convert.ToString(f2.X_max));
                //textBox2.Text = Convert.ToString(f2.X_min);
                //textBox3.Text = Convert.ToString(f2.X_max);

            }
     

}

Danke!

16.806 Beiträge seit 2008
vor 6 Jahren

welchen wert hat x_max

wie gesagt, der debugger lügt nicht.

D
Delfis Themenstarter:in
24 Beiträge seit 2017
vor 6 Jahren

Hallo Benjamin,

folgende Werte habe ich eingegeben: k=2, xmin=1,31 und xmax=4,25. Wie gesagt werden diese Werte in der Messagebox richtig angezeigt, die Textfelder bleiben leer selbst wenn ich z. B. textBox1.Text="test" eingebe.
Hier noch die Konstruktoren für die Werteübergabe aus Form2:


        private string kal;
        public string Kal
        {
            get => kal; set => kal = value;
        }
        private decimal xmin;
        public decimal X_min
        {
            get => xmin; set => xmin = value;
        }
        private decimal xmax;
        public decimal X_max
        {
            get => xmax; set => xmax = value;
        }

Danke!

H
523 Beiträge seit 2008
vor 6 Jahren

Ich wüsste nicht warum das Füllen der Textboxen nicht funktionieren sollte.


    public partial class Form1 : Form
    {
        public Form1()
        {
            InitializeComponent();
        }

        private void button1_Click(object sender, EventArgs e)
        {
            Form2 form = new Form2();
            DialogResult result = form.ShowDialog();

            if (result == DialogResult.OK)
            {
                this.textBox1.Text = form.Kal;
                this.textBox2.Text = Convert.ToString(form.X_max);
                this.textBox3.Text = Convert.ToString(form.X_min);
            }

            MessageBox.Show(result.ToString());
        }
    }


    public partial class Form2 : Form
    {
        public string Kal { get; set; }
        public decimal X_min { get; set; }
        public decimal X_max { get; set; }


        public Form2()
        {
            InitializeComponent();
            this.Kal = "test";
            this.X_min =(decimal)1.31;
            this.X_max = (decimal)4.25;
        }

        private void button1_Click(object sender, EventArgs e)
        {
            this.DialogResult = DialogResult.OK;
            this.Close();
        }
    }

Leerst Du die Textboxen an irgendeiner Stelle? Ansonsten einfach mal mehr Code und nicht nur Ausschnitte posten.

4.931 Beiträge seit 2008
vor 6 Jahren

Noch als Hinweis: Man kann den Button.DialogResult auch schon im Designer (für den Button) setzen, so daß dafür kein eigener Code geschrieben werden muß.

16.806 Beiträge seit 2008
vor 6 Jahren

die Textfelder bleiben leer selbst wenn ich z. B. textBox1.Text="test" eingebe.

Das ist ja schon eindeutig, dass Du irgenwo den Text wieder überschreibst.
Wo: das sehen wir hier nicht.

Schau Dir dazu alle entsprechenden textBox1 Stellen an (Find all references).

D
Delfis Themenstarter:in
24 Beiträge seit 2017
vor 6 Jahren

Ich habe den Fehler gefunden! Beim Starten des Programms wunderte ich mich, warum das Toolstripmenu doppelt dargestellt wurde. Nachdem ich nun das zweite "InitialiseComponent" auskommentiert habe, tritt das nicht mehr auf und die Textboxen werden mit den Werten gefüllt. Vorher funktionierte das genauso wenig mit Labeln. Wie die zweite Initialisierung dorthin gekommen ist, kann ich nicht mehr nachvollziehen.

Danke dennoch für Eure Hilfe. Manchmal reicht es schon, wenn kompetente Ansprechpartner in Reichweite sind!
In diesem Zusammenhang ergibt sich eine zweite Frage. Statt wie in diesem Falle mit einer Variablen "Kal" zu arbeiten, müsste es doch wie bei dem DialogResult auch möglich sein, das Ergebnis der Radiobutton-Auswahl direkt in die Form1 übertragen zu können. Wie müsste das dann aussehen?
Hier nochmals der vollständige Code.:

Code Form1:


using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Data;
using System.Drawing;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using System.Windows.Forms;

namespace WindowsFormsApp1
{
    public partial class Form1 : Form
    {
        public Form1()
        {
            InitializeComponent();
        }

        private void Form1_Load(object sender, EventArgs e)
        {
[/B]      InitializeComponent();
        }

        private void BeendenStripMenuItem_Click(object sender, EventArgs e)
        {
            Close();
        }

        private void AchsenkalibrierungToolStripMenuItem_Click(object sender, EventArgs e)
        {

            Form2 f2 = new Form2();
            DialogResult result = f2.ShowDialog();

            if (result == DialogResult.OK)
            {
                textBox1.Text = f2.Kal;
                textBox2.Text = Convert.ToString(f2.X_min);
                textBox3.Text = Convert.ToString(f2.X_max);
                MessageBox.Show(f2.Kal + " " + Convert.ToString(f2.X_min) + " " + Convert.ToString(f2.X_max));
            }
        }
    }
}

Code Form2:

using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Data;
using System.Drawing;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using System.Windows.Forms;

namespace WindowsFormsApp1
{
    public partial class Form2 : Form
    {
        private string kal;
        public string Kal
        {
            get => kal; set => kal = value;
        }
        private decimal xmin;
        public decimal X_min
        {
            get => xmin; set => xmin = value;
        }
        private decimal xmax;
        public decimal X_max
        {
            get => xmax; set => xmax = value;
        }
        public Form2()
        {
            InitializeComponent();
        }

        private void Xy_l_CheckedChanged(object sender, EventArgs e)
        {
            if (Xy_l.Checked)
            {
                Kal = "1";            }
        }

        private void Xl_ylog_CheckedChanged(object sender, EventArgs e)
        {
            if (Xl_ylog.Checked)
            {
                Kal = "2";
            }
        }

        private void Xlog_yl_CheckedChanged(object sender, EventArgs e)
        {
            if (Xlog_yl.Checked)
            {
                Kal = "3";
            }
        }

        private void Xlog_ylog_CheckedChanged(object sender, EventArgs e)
        {
            if (Xlog_ylog.Checked)
            {
                Kal = "4";
            }
        }

        private void button1_Click(object sender, EventArgs e)
        {
            X_min = Convert.ToDecimal(Xmin_box.Text);
            X_max= Convert.ToDecimal(Xmax_box.Text);
            this.DialogResult = DialogResult.OK;
            this.Close();
        }
    }
}


H
523 Beiträge seit 2008
vor 6 Jahren

Es gibt verschiedene Möglichkeiten wie Du die Rückgabe des ausgewählten Radiobuttons umsetzen kannst. Mit der Variable liegst Du eigentlich schon ganz gut. Anstatt mit Events zu arbeiten würde ich die Variable "Kal" unmittelbar vor dem Schließen der Form setzen.

Theoretisch könntest Du auch die Eigenschaft "Modifiers" der Radiobuttons auf "Public" setzen um dann direkt, von der ersten Form aus, auf die Radiobuttons zugreifen zu können. Das halte ich persönlich aber für eine unschöne Vorgehensweise.

1.029 Beiträge seit 2010
vor 6 Jahren

Hi,

in meinen Augen ist das Property "Kal" eigentlich nicht die verkehrte Wahl.

Form2 sollte Form1 nicht einmal kennen -> hälst du ein.
Die Nutzung eines Events bringt dir hier keinen Vorteil.
Die RadioButtons von Form2 in Form1 direkt zu benutzen wäre unklug.

Allerdings lässt sich die Implementierung des Properties und der Form sehr viel einfacher gestalten indem du die ganzen EventHandler für die Checkboxen weglässt, den Setter von "Kal" weglässt und den Getter so implementierst, dass kurz die Checkboxen abgefragt werden.

LG

D
Delfis Themenstarter:in
24 Beiträge seit 2017
vor 6 Jahren

Hallo Taipi88 und hyperserf,

nachdem, was ich bislang über Klassen gelesen habe, ist es also der logisch bessere Weg, Daten quasi indirekt auszutauschen und die Routinen als eigenständig bestehen zu lassen. Diese Programmierweise ist nach meinen Erfahrungen mit dem Arduino allerdings noch gewöhnungsbedürftig.

@Taipi88: Ich habe versucht, Dein Beispiel umzusetzen, meintest Du das -mithilfe meines Handbuches- in etwa so:


using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Data;
using System.Drawing;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using System.Windows.Forms;

namespace WindowsFormsApp1
{
    public partial class Form2 : Form
    {
        private string kal;
        public string Kal
        {
            get
            {
                return kal;
            }
            private set
            {
                if (Xy_l.Checked)
                {
                    kal = "1";
                }
                else if (Xl_ylog.Checked)
                {
                    kal = "2";
                }
                else if (Xlog_yl.Checked)
                {
                    kal = "3";
                }
                else 
                {
                    kal = "4";
                }
            }
        }
        private decimal xmin;
        public decimal X_min
        {
            get => xmin; set => xmin = value;
        }
        private decimal xmax;
        public decimal X_max
        {
            get => xmax; set => xmax = value;
        }
        public Form2()
        {
            InitializeComponent();
        }

        private void button1_Click(object sender, EventArgs e)
        {
            X_min = Convert.ToDecimal(Xmin_box.Text);
            X_max= Convert.ToDecimal(Xmax_box.Text);
            this.DialogResult = DialogResult.OK;
            this.Close();
        }
    }
}


Das funktioniert prima und sieht erheblich eleganter aus, ein super Tipp bis auf eine Kleinigkeit: der erste Radiobutton ist automatisch im Entwurfsmodus und beim Aufruf der Form2 aktiviert. Der korrekte Wert "1" für kal wird aber erst dann richtig zugeordnet, nachdem ich zwischenzeitlich einen anderen Radiobutton aktiviert hatte, ansonsten bleibt die Rückgabe leer. Wie kann ich das noch vervollständigen?

Danke!

1.029 Beiträge seit 2010
vor 6 Jahren

Hi,

du hast leider auch nicht so implementiert wie ich das empfohlen hatte 😉

Wundert mich ehrlich gesagt, dass da überhaupt was funktioniert, da der Setter (den du weglassen solltest) hier nicht einmal aufgerufen wird. Richtig wäre:


public string Kal
{
	get
	{
		if (Xy_l.Checked)
			return "1";
		if (Xl_ylog.Checked)
			return "2";
		if (Xlog_yl.Checked)
			return "3";
		return "4";
	}
}

LG

PS: Es ist sehr befremdlich, dass du Zahlen als String überträgst. Wieso eigentlich kein int?

PPS: Properties die keine zusätzlichen Sachen in getter und setter machen kann man übrigens auch vereinfacht folgendermaßen schreiben:


public decimal X_max {get;set;}

D
Delfis Themenstarter:in
24 Beiträge seit 2017
vor 6 Jahren

Hallo Taipi88,

das sieht natürlich noch besser aus. Wie gesagt, bin ich dabei, mich auf objektorientierte Programmierung umzustellen und stehe noch am Anfang.

Stimmt, statt die Zahlen als String zu verwenden, könnte ich sie besser so belassen. Das werde ich ändern genauso wie die x-Werte. Das Beispiel ist anhand eines Progammbeispieles aus "Einstieg in Visual C# 2013" übernommen.

Gruß
Thomas

D
Delfis Themenstarter:in
24 Beiträge seit 2017
vor 6 Jahren

Hallo Taipi88,

eine Frag ist noch ungeklärt: Wieso wird die Voreinstellung des ersten Radiobuttons nicht korrekt an Kal übergeben sondern erst, nachdem zwischenzeitlich ein anderer Radiobutton ausgewählt worden ist. Wie kann ich das ändern?

In der Form1 habe ich natürlich den uint Kal in einen String umgewandelt, um ihn in der Textbox richtig ausgeben zu können. Ansonsten hoffe ich, dass nun alles passt:

  
using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Data;
using System.Drawing;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using System.Windows.Forms;

namespace WindowsFormsApp1
{
    public partial class Form2 : Form
    {
        public uint Kal
        {
            get
            {
                if (Xy_l.Checked)
                    return 1;
                if (Xl_ylog.Checked)
                    return 2;
                if (Xlog_yl.Checked)
                    return 3;
                return 4;
            }
        }
        public decimal X_min {get; set;}
        public decimal X_max { get; set; }

        public Form2()
        {
            InitializeComponent();
        }

        private void button1_Click(object sender, EventArgs e)
        {
            X_min = Convert.ToDecimal(Xmin_box.Text);
            X_max= Convert.ToDecimal(Xmax_box.Text);
            this.DialogResult = DialogResult.OK;
            this.Close();
        }
    }
}


Übrigens wirft der Debugger nun vier Fehlermeldungen aus, weil keine ..._CheckedChange Methoden gefunden werden. Da das Programm ansonsten läuft, spielt das wohl keine Rolle, oder?

1.029 Beiträge seit 2010
vor 6 Jahren

Hi,

doch das spielt eine Rolle - du startest nämlich damit eine alte Version deines Programms, womit deine aktuellen Änderungen keine Rolle spielen.

Grund für die 4 Fehler sind die einfach von dir entfernen Ereignisbehandlungsmethoden.

Wenn du in deine Form2.Designer.cs-Datei reinschaust (ist hinter Form2.cs versteckt) wirst du 4 rot markierte Anweisungen finden die du löschen musst.
Sehen ungefähr folgendermaßen aus:


Xl_ylog.CheckedChanged += Xl_ylog_CheckedChanged;

Das kommt daher, dass der Designer nicht riechen kann wenn du in deiner Code-Datei was löschst.

Ich denke wenn du das korrigiert hast - ist auch der Fehler weg - falls nicht - kannst du schauen, ob es hilft, wenn du im Konstruktor (nach InitializeComponent) folgendes quasi als Startwert schreibst:


Xy_l.Checked = true;

LG

PS: Wenn du Fehlermeldungen bekommst - lies diese besser genau 😉

D
Delfis Themenstarter:in
24 Beiträge seit 2017
vor 6 Jahren

Hallo Taipi88,

dieses Forum ist eine große Hilfe für mich, seit gestern habe ich eine Menge dazu gelernt, vor allem, dass in C# mehrere Baustellen gleichzeitig im Auge behalten werden müssen. Bei Arduino C gab es nur die direkten Korrekturen im Programm, hier ist es eine weitere Datei.

Die entsprechenden Zeilen im Form2-Designer sind gelöscht und die Fehler verschwunden, auch ohne die zusätzliche Programmzeile erfolgt nun die richtige Zuordnung zur Variablen Kal.

Danke nochmals, mal schauen, wie ich nun weiterkomme.

Thomas

5.299 Beiträge seit 2008
vor 6 Jahren

Du kannst im FormDesigner das DialogResult von Buttons festlegen, damit bewirkst du gleichzeitig, dass diese Buttons das Form schließen - ohne weiteren Code schreiben zu müssen.
gugge Filmle: Dialoge implementieren
Indem du so den Designer seinen Job machen lässt, entfällt der Button-Klick-Code, und wird insgesamt merklich einfacher:

//nur nötige usings
using System;
using System.Collections.Generic;
using System.Linq;
using System.Windows.Forms;

namespace WindowsFormsApp1 {
   public partial class Form2 : Form {
      public uint Kal {
         get { // ifs ohne {} einzeilig notieren
            if (Xy_l.Checked) return 1;
            if (Xl_ylog.Checked) return 2;
            if (Xlog_yl.Checked) return 3;
            return 4;
         }
      }
      // readonly props, die ihren Wert selbst ermitteln (kein BackingField)
      public decimal X_min { get {return Convert.ToDecimal(Xmin_box.Text); } }
      public decimal X_max { get { return Convert.ToDecimal(Xmax_box.Text); } }

      public Form2() {
         InitializeComponent();
      }
   }
}

Wobei das problematisch ist, decimal-Werte aus Textboxen zu lesen - das stürzt ab, wenn da jemand "Hallo Welt" reinschreibt.
Für Zahlen-Eingaben NumericUpdown nehmen.

Der frühe Apfel fängt den Wurm.