Komunikacja w aplikacji wielookienkowej. Znaczenie zmiennych globalnych (publicznych)
Materiał jest kontynuacją tematu poprzedniego Aplikacja wielookienkowa, stąd sposobu dodawania kolejnych formatek okien nie będę w tym temacie opisywać. Temat obejmuje zagadnienia wykorzystania zmiennych publicznych w aplikacji wielookienkowej MDI.
Cel: Napisz aplikację wielookienkową przy pomocy której będzie można zamykać lub otwierać okna dzieci z innych okien potomnych oraz wykonując działania na zmiennych publicznych zadeklarowanych w różnych oknach.

Krok 1. Układ komponentów w oknach dzieci
Ze względu na tematyczne podzielenie okien potomnych na dwie grupy w poprzednim temacie układ komponentów w oknach dzieci będzie dobrany pod metodę ich wywołania. Czyli wywołanie bezpośrednie i poprzez instancję klasy okna formatki dziecka.
Okna wywoływane bezpośrednio powinny zawierać układ komponentów jak poniżej
Okno numer 1 (formatka Form2) zawiera dwa komponenty Button. Przy ich pomocy będzie można otwierać okno 2 (Form3) i okno 4 (Form4)
Okno numer 2 (formatka Form3) zawiera jeden komponent Button, przy pomocy którego zamknie się okno 1 (Form2)

Okno numer 3 (formatka Form4) zawiera jeden komponent Button, przy pomocy którego zamknie się okno 2 (Form3)

Układ komponentów na formatkach okien wywoływanych przez instancję klasy
Okno pierwsze instancji (formatka Form5) zawiera dwa komponenty Button, przy pomocy których można otworzyć okno 2 instancji (Form6) i okno 4 instancji (Form7)

Okno 2 instancji (formatka Form6) zawiera po dwa komponenty Label, TextBox i Button.
W komponentach TextBox będzie można wprowadzić zmienne publiczne zapisane w oknie 3 instancji (Form7).

Komponenty Button pozwolą wykonać odpowiednie działanie i pokazać wynik w oknie 3 po jego wywołaniu. Sposób przeprowadzenia tych działań będzie bazować na różnych sposobach obsługi zmiennych publicznych.
Okno 3 instancji (formatka Form7) zawiera dwa komponenty Label. Komponent label1 zawiera statyczny tekst "Wynik działania z okna II". Komponent label2 będzie służyć do przedstawienia tego wyniku

Krok 2. Polecenie otwarcia okna dziecka z innego okna dziecka w metodzie wywołania bezpośredniego
Rozwiązanie oparte jest na wywołaniu publicznej funkcji RobOkno zapisanej w kodzie klasy okna głównego (ojca aplikacji wielookienkowej). Ciało funkcji RobOkno znajduje się w poprzednim temacie
Dla przycisku wywołującego okno 2 (Form3)
private void Button1_Click(object sender, EventArgs e)
{
//rzutuj na uchwyt ojca
Form1 f = (Form1)this.MdiParent;
if (f.form3 == null) {
f.form3 = new Form3();
f.RobOkno(f.form3, "okno2");
}
else f.form3.Activate();
}
Dla przycisku wywołującego okno 3 (Form4) przedstawię nieznaczną modyfikację wywołania funkcji RobOkno
private void Button2_Click(object sender, EventArgs e)
{
//rzutuj na uchwyt ojca
Form1 f = (Form1)this.MdiParent;
if (f.form4 == null)f.RobOkno(f.form4 = new Form4(), "okno3");
else f.form4.Activate();
}
Skompiluj program i sprawdź efekt działania
Krok 3. Zamknięcie okna dziecka z poziomu innego okna dziecka w aplikacji wielookienkowej w metodzie wywołania bezpośredniego
Zamykamy okno 1 (Form2) z okna 2 (Form3). Kod zdarzenia Click dla przycisku button1 w formatce Form3
private void Button1_Click(object sender, EventArgs e)
{
//rzutuj na uchwyt ojca
Form1 f = (Form1)this.MdiParent;
//zamknij okno1
if(f.form2!=null)f.form2.Close();
}
W podobny sposób zamkniemy okno 2 (Form3) z okna 3 (Form4). Kod zdarzenia Click dla przycisku button1 w formatce Form4
private void Button1_Click(object sender, EventArgs e)
{
//rzutuj na uchwyt ojca
Form1 f = (Form1)this.MdiParent;
//zamknij okno1
if(f.form2!=null)f.form2.Close();
}
Skompiluj program i sprawdź efekt działania.
Rozwiązanie dla okien wywoływanych poprzez instancję klasy
Metoda używania instancji jest wygodniejsza przy obsłudze zmiennych i funkcji publicznych pomimo, że wymaga powtórzenia tego samego kodu w kolejnych klasach dodawanych okien dzieci.
Krok 1. Wywołanie okna dziecka z poziomu innego okna dziecka
Kod zdarzenia Click przycisku button1 formatki Form5
private void Button1_Click(object sender, EventArgs e)
{
Form6.Instancja.MdiParent = this.MdiParent;
Form6.Instancja.Text="Okno II otwarte z okna I";
Form6.Instancja.Show();
Form6.Instancja.Activate();
}
Kod zdarzenia Click przycisku button2 formatki Form5
private void Button2_Click(object sender, EventArgs e)
{
Form7.Instancja.MdiParent = this.MdiParent;
Form7.Instancja.Text = "Okno III otwarte z okna I";
Form7.Instancja.Show();
Form6.Instancja.Activate();
}
Skompiluj program i sprawdź efekt działania. Działająca aplikacja pozwoli otworzyć okna dzieci z poziomu okna pierwszego dziecka

Krok 2. Deklarujemy zmienne publiczne i funkcję publiczną w Form7
W oknie 2 (Form6) będziemy pracować na zmiennych zadeklarowanych w innej klasie. Zmienne te muszą mieć charakter publiczny. Deklarujemy dwie publiczne zmienne typu rzeczywistego
public partial class Form7 : Form
{
public float a, b;
Ze względu na ćwiczeniowy charakter tej aplikacji pokażę dwie metody użycia komponentu Label z poziomu innego okna dziecka. Do tego celu będzie potrzebna publiczna zmienna rzutowania na komponent Label
public float a, b;
public Label _label2 => label2;
I dla drugiego sposobu- publiczna funkcja
public void Dodawanie()
{
label2.Text = a.ToString()+"+"+b.ToString()+"="+(a + b).ToString();
}
Krok 3. Użycie publicznej funkcji w innej klasie okna dziecka
W zdarzeniu Click przycisku button1 w Form6 odwołamy się do zmiennych a i b oraz funkcji Dodaj z klasy okna Form7. Po przypisaniu im wartości w oknie klasy Form6 wyślemy wynik dodawania do okna Form7. Kod, który to umożliwi może przyjąć poniższą postać
private void Button1_Click(object sender, EventArgs e)
{
Form7.Instancja.a = (float)Convert.ToDouble(textBox1.Text);
Form7.Instancja.b = (float)Convert.ToDouble(textBox2.Text);
Form7.Instancja.MdiParent = this.MdiParent;
Form7.Instancja.Text = "Okno III otwarte z okna II";
Form7.Instancja.Dodawanie();
Form7.Instancja.Show();
Form7.Instancja.Activate();
}
Skompiluj program i sprawdź efekt działania. Prawidłowo działając aplikacja zachowuj się jak poniżej

Krok 4. Użycie publicznego rzutowania na komponent okna dziecka
Tu przedstawię inne podejście do sterowani zmiennymi zewnętrznej klasy okna dziecka w oknie klasy innego dziecka. Działanie jest bardzo podobne jak w kroku 3, z tą różnicą, że wykorzystujemy bezpośrednio właściwości komponentu poprzez jego rzutowanie.
Kod zdarzenia Click drugiego przycisku button2 formatki Form6 zawiera poniższe wiersze
private void Button2_Click(object sender, EventArgs e)
{
float a = (float)Convert.ToDouble(textBox1.Text);
float b = (float)Convert.ToDouble(textBox2.Text);
Form7.Instancja.MdiParent = this.MdiParent;
Form7.Instancja.Text = "Okno III otwarte z okna II";
Form7.Instancja._label2.Text= a.ToString() + "*" + b.ToString() + "=" + (a * b).ToString();
Form7.Instancja.Show();
Form7.Instancja.Activate();
}
Kompilacja aplikacji pozwoli uzyskać poniższe zachowanie się programu

Ćwiczenie sprawdzające: Zabezpiecz aplikację przed błędami konwersji