Interakce mezi okny v WPF

Jaký by byl kurz sázek na to, zda bude vybraná desktopová aplikace používat více než jedno okno? Mizivý… Dá se předpokládat, že hlavní průzor do duše programu doplní další okénka – dialogy, reporty, monology… Spolu s tím bude potřeba řešit, jak mezi nimi zajistit plynulou komunikaci. Podívejme se, jak na to v WPF.

Poznámka bokem: Možná vám připadá zvláštní spojení „v WPF“, i mně se zdá krátká předložka všelijaká. Vychází ovšem z toho, že mám ve zvyku číst WPF po anglicku, tedy „dabljů-pí-ef“. Zkuste si to, pak už to dává smysl ;).

Co je vlastně myšleno komunikací mezi okny? To hlavní vytvoří instanci podokna (dejme tomu jednoduchého dialogu), do kterého uživatel zadá nějaké informace (třeba jméno a příjmení nového kamaráda). Pochopitelně je žádoucí, aby se data nějakým způsobem dostala do paměťových pařátů hlavního okna, protože existence dialogu končí s jeho zavřením (není to nutné, nicméně běžné a v našem imaginárním programu jsme tak rozhodli).

WPF nabízí několik možností, jak si informace mezi okny předat.

Application.Current.MainWindow

Za prvé je každému oknu dostupná vlastnost MainWindow, která vrací odkaz na instanci toho hlavního z nich.

Window main = Application.Current.MainWindow; // vlastnost MainWindow představuje hlavní okno
Window win = Application.Current.Windows[0]; // kolekce Windows obsahuje všechna okna aplikace

Jakmile získáme odkaz na okno, znamená to, že můžeme pracovat s jeho vlastnostmi a metodami (v našem případě třeba přímo vložit novou položku do veřejné kolekce kamarádů).

main.Friends.Add(...);

Tento postup je funkční, ale ne zcela korektní. Doporučuje se raději v cílovém okně vytvořit speciální metodu a nesahat na jeho data přímo.

main.AddFriend(...);

Dialog model

Pro potřeby zmíněné aplikace je druhé okno (zadání jména a příjmení) dialogem, na což WPF samozřejmě pamatuje a umožňuje jej zobrazit metodou ShowDialog(). V takovém případě program čeká na to, co z okna vyleze, a je připraven data zpracovat.

Jak mu tedy povíme, že informace jsou k dispozici a je třeba je přijmout? Poslouží vlastnost DialogResult, kterou oplývá každé okno a která je návratovou hodnotou metody ShowDialog(). DialogResult je typu bool?, což znamená, že může mít hodnotu true, false nebo null.

Hodnoty false automaticky nabyde, pokud:

  • je okno zavřeno křížkem,
  • je okno zavřeno příkazem Zavřít ze systémové nabídky (v levém horním rohu okna),
  • je okno zavřeno klávesovou zkratkou Alt+F4.

A aby byl výčet nepravd kompletní, DialogResult je také automaticky nastaven na false, pokud je zmáčknuto tlačítko, které má nastaveno IsCancel na true (viz obrázek). Stiskne-li uživatel klávesu Esc, je vyvolána událost Click() takového tlačítka, okno se uzavře a ShowDialog() vrátí false.

Naopak hodnotu true musíme nastavit ručně, třeba v obsluze kliknutí na potvrzovací tlačítko (viz obrázek níže). Pokud mu navíc aktivujeme vlastnost IsDefault, nebude nutné na něj ani používat myš, postačí kdekoliv stisknout klávesu Enter.

A jak hlavní okno přečte data? Jednoduše si je vytáhne z veřejných vlastností definovaných v dialogu. Kód doplněný obrázky napoví…

// Dialogové okno.
public partial class winAdd : Window {
	public string Jmeno { get; set; }
	public string Prijmeni { get; set; }

	public winAdd() {
		InitializeComponent();
	}

	private void buttOk_Click(object sender, RoutedEventArgs e) {
		Jmeno = txtJmeno.Text;
		Prijmeni = txtPrijmeni.Text;
		DialogResult = true; // je třeba nastavit ručně, přestože tlačítko je označeno jako IsDefault
		// okno se samo uzavře
	}
}

// Hlavní okno.
public partial class MainWindow : Window {
	public MainWindow() {
		InitializeComponent();
	}

	private void buttPridat_Click(object sender, RoutedEventArgs e) {
		winAdd wAdd = new winAdd();
		if (wAdd.ShowDialog() == true) {
			txtJmeno.Text = wAdd.Jmeno;
			txtPrijmeni.Text = wAdd.Prijmeni;
		}
	}
}

Možností je samozřejmě více, ale tyto dvě mi stojí za zaznamenání :).

3 thoughts on “Interakce mezi okny v WPF

  1. Snake.Bite

    Stačilo by napsat „v prostředí WPF“ nebo „pomocí WPF“ ;)
    Jinak pěkný článek. DialogResult není nic nového, ale o tom, že lze přidat k názvu proměnné ‚?‘ a vynutit tak další stav null, jsem nevěděl. Takže děkuji :)

  2. DeedX Post author

    Díky :)
    Otazníkem se hodnotové datové typy označují jako nullable a je možné si dovolit stejný komfort jako u referenčních typů – uložit do nich null (což je konzistentnější řešení, než volit nějakou hodnotu, která z logiky dané aplikace nemá smysl, třeba -1).

  3. TypekTypek

    Fajn navod, len malicka uprava treba mat property nastavene na static, inak mi to nechcelo fungovat, Dik

Napsat komentář

Vaše e-mailová adresa nebude zveřejněna. Vyžadované informace jsou označeny *