Windows Forms .NET tutoriaali C

Mureakuha

Loikkaa: valikkoon, hakuun

(c) Marko Parkkola

Tämä dokumentti antaa lukijalle peruslähtökohdat Windows Formsien käyttöön .NET ympäristössä. Ohjelmointikielenä käytetään C#:ia, mutta koodiesimerkit ovat kohtuullisen helppo muuttaa esim. VB.NET ympäristöön. Ympäristönä on käytetty Visual Studio 2003 .NET:iä, kaikki lomakkeet ym. on tuotettu sillä.

Alku

Luo Visual Studiolla uusi Windows Application ja nimeä se nimelle WinFormsTutorial1. Voit käyttää toki muutakin nimeä, mutta saatan viitata dokumentin myöhemmässä vaiheessa tähän nimeen. Visual Studio luo sinulle Solution työympäristön ja Windows Application projektin. Jos katsot tiedostojärjestelmästä sitä kohtaa, johon Visual Studio luo projektit (yleensä My Documents\Visual Studio Projects) näet, että Visual Studio on luonut uuden hakemiston ja kasan tiedostoja sinne. Tässä tapauksessa järjestelmästä pitäisi löytyä seuraavat tiedostot:

My Documents\Visual Studio Projects\WinFormsTutorial1
  bin\
    debug\				- Käännetty debug binääri tulee tänne
  obj\
    debug\
      temp\
      tempPE\
app.ico				- Ohjelman ikoni
AssemblyInfo.cs			- Yleisiä tietoja projektistä
Form1.cs				- Tänne kirjoitetaan kaikki formiin liittyvä logiikka
Form1.resx				- XML tiedosto, jossa kuvataan formin ulkoasu
WinFormsTutorial1.csproj	- Projektitiedosto
WinFormsTutorial1.csproj.user	- Käyttäjän asetuksia projektiin liittyen
WinFormsTutorial1.sln		- Solution työympäristö

Tässä hieman tietoa, mitä eri tiedostot merkitsevät. Nämä kaikki voitaisiin hyvin kirjoittaa käsinkin, mutta annetaan IDE:n hoitaa kaikki tylsä XML:n yms. kirjoittaminen.

Seuraavaksi vilkaistaanpa itse formia...

Visual Studio luo automaattisesti formin nimeltä Form1 meille. Nimi ei ole oikein kuvaava ajatellen sitä, mitä olemme tässä tekemässä. Vaihdetaanpa nimi seuraavasti. Klikkaa hiiren oikealla napilla formia ja valitse Properties. Sinulle aukeaa eteen properties ikkuna tai sitten kohdistus siirtyy properties valikkoon, riippuu asetuksistasi. Etsi sieltä kohta Name ja vaihda siihen MainForm, etsi myös kohta Text ja vaihda siihen My File Browser. Ikkuna on myös turhan pieni, joten venytä sitä isommaksi tai muuta propertiesistä kohtaa Size, 500; 400 on varmaan ihan hyvä koko.

Seuraavaksi lisää formiin TreeView komponenetti. Valitse komponentti ja vaihda sen nimi (Name kenttä propertiesissä) FolderView:ksi. Laita myös Dock arvoksi Left, jotta komponentti menee nätisti formin vasempaan laitaan ja pysyy siellä.

Tämän jälkeen lisää Splitter komponentti formille TreeViewin oikealle puolelle. Splitterille ei tarvitse määrittää erityisiä propertiesejä.

Lopuksi lisää formille ListBox komponentti ja muuta sen nimi FileView:ksi ja Dock:ksi Fill. Joudut ehkä vähän kutistamaan formia pystysuunnasta, sillä jostain syystä ListBox ei veny tarpeeksi korkeaksi.

Käännä projekti valitsemalla Build valikosta Build Solution. Build käsky saattaa löytyä myös näppäinyhdistelmän CTRL+SHIFT+B takaa. En ole varma, sillä bindasin itse ko. käskyn F7 näppäimen taakse. Kääntäminen antaa nyt meille virheen, koska muutimme formin nimeä ja tämä ei päivittynyt koodiin. Visual Studion alalaidassa olevaan valkoiseen tilaan ilmestyy virhe:

The type or namespace name 'Form1' could not be found (are you missing a using directive or an assembly reference?)

Tuplaklikkaamalla tätä pääset koodissa siihen kohtaa, missä virhe tapahtuu ja aivan oikein, siellähän lukee vielä Application.Run(new Form1()); Muuta tästä nyt tuo Form1 nimi muotoon MainForm ja ohjelma kääntyy. Debug valikosta Start (tai F5) käynnistää ohjelmasi debuggeriin ja pääset ihastelemaan formisi ulkonäköä. Seuraavaksi tutkitaan hieman koodia.

Koodi

Valitse Solution Explorerista Form1.cs. Valitse oiken hiirennapin takaa Rename ja vaihda nimi MainForm.cs:ksi. Tämän jälkeen valitse oikean hiirennapin takaa View Code ja pääset koodiin, jossa itseasiassa kävimmekin äsken korjaamassa asioita.

Kuten huomaat, Visual Studio on ystävällisesti luonut sinulle kasan koodia valmiiksi. Ensimmäisenä koodissa on using lauseet. Nämä tuovat nimiavaruuksia käännösyksikön käyttöön, jotta koodaajan ei tarvitsisi kirjoittaa luokkien kokonaisia nimiä koodiin joka kerta. Seuraavaksi tulee ohjelmasi oma nimiavaruus, tässä tapauksessa WinFormsTutorial1. Tämän sisällä on sitten luokka, joka hoitaa formin alustuksen ja tapauskäsittelijät. Luokka on peritty System.Windows.Forms.Form yläluokasta, jotta saamme kaikki formiin liittyvät tominnot käyttöömme. Luokan muuttujina ovat äsken luomamme kolme komponenttia, sekä container luokka komponenteille (älä vaivaa tällä päätäsi suotta).

Seuraavaksi käsitellään hieman luokan metodeja. Konstruktorilla ei ole paljon tehtäviä, se kutsuu vain InitializeComponent metodia asettamaan alkuarvot äsken luomillemme komponenteille, sekä tietysti lisäämään ne formille.

Dispose metodi ylikirjoittaa yläluokan Dispose metodin jolloin voimme tehdä oman toteutuksen siihen, mitä tapahtuu, kun luokka tuhotaan. Eräänlainen destruktori siis.

Seuraavaksi huomaamme, että Visual Studio on piilottanut meiltä hieman koodia. Tämä on järkevää, sillä yleensä ottaen koodaajan ei tarvitse itse mennä säätämään InitializeComponent metodia, vaan IDE hoitaa sen puolestamme. Voit kuitenkin huoletta avata tämän koodiblokin painamalla vasemmalla olevaan + merkkiä ja vilkaista hieman mitä siellä tapahtuu. Merkittävät kohdat ovat kutsut SuspendLayout, joka estää formia päivättämästä itseään ja ResumeLayout, joka sallii formin päivityksen jatkuvan. Ilman näitä kutsuja ikkuna välkkyisi ikävästä, kun komponentteja sijoitellaan paikoilleen.

Lopuksi pääsemma Main metodiin, josta kaikki alkaa. Main metodin ainoa tehtävä on luoda formi ja käynnistää applikaatio ajamaan formia.

Ohjelmamme tarvitsee luokkia System.IO ja System.Diagnostics nimiavaruuksista, joten mene koodissa using lauseisiin ja lisää olemassa olevien lauseiden alle using System.IO; ja using System.Diagnostics;

Palataanpa nyt takaisin forminäkymään valitsemalla koodialueen yläpuolelta MainForm.cs [Design] tabi. Nyt luomme tapahtumakäsittelijän, jota kutsutaan heti, kun formi luodaan. Valitse properties ikkunan pudotusvalikosta MainForm ja napsauta sitä salaman näköistä nappia pudotusvalikon alapuolella, jotta pääset käsittelemään eventtejä. Tuplaklikkaa sieltä kohtaa Load ja pääset automaattisesti takaisin koodinäkymään Load eventtiin.

Enumeroidaanpa aluksi kaikki loogiset asemat mitä koneesta löytyy. Harrastetaan myös hiukan poikkeustenkäsittelyä ohjelmassamme.

private void MainForm_Load(object sender, System.EventArgs e) {
	try {
		string[] names = Directory.GetLogicalDrives();
		foreach (string name in names) {
			// Remove \ character from string to ease up later steps
			TreeNode node = new TreeNode(name.Replace("\\", ""));
			node.Nodes.Add(new TreeNode("."));
			FolderView.Nodes.Add(node);	
		}
	}
	catch (Exception ex) {
		MessageBox.Show(ex.ToString());
	}
}

try - catch lohko on siis poikkeuksia varten. Jos jokin kutsuistamme epäonnistuisi ja heittäisi poikkeuksen, se päätyisi catch lohkoon (koska kaikki poikkeukset pitää periä Exception luokasta, saa ne kaikki kiinni tällä tavalla), jossa näyttäisimme käyttäjälle erittäin sekavan virheilmoituksen. Jokainen luokka peritään Object kantaluokasta C#:ssa, jolloinka jokaisella luokalla on ToString metodi, joka palauttaa oliosta jonkin stringin, tässä tapauksessa sekavan selosteen virheestä.

Ensimmäisellä koodirivillä kutsumme Directory luokan GetLogicalDrives staattista metodia, joka palauttaa meille taulukon string olioita. Jokainen string olio pitää sisällään yhden loogisen aseman nimen. Käymme nämä nimet läpi foreach silmukassa, jossa lisäämme FolderViewiin asemien nimet. Lisäämme myös jokaiselle nodelle yhden turhan lapsinoden, jotta saamme FolderViewiin kauniin + merkin näkyville, josta käyttäjä sitten avaa ko. aseman.

Tarkemmat selostukset metodeista ja luokista kannattaa lukea MSDN:stä. Jos nyt käännät ohjelman ja ajat sen huomaat, että kaikki koneesi asemat on lueteltuina FolderView komponentissa.

Palataanpa takaisin formin desing näyttöön ja valitaan FolderView ja mennään sen eventteihin. Tuplaklikkaa kohtaa BeforeExpand. Tänne kirjoitetaan koodi mikä suoritetaan, kun käyttäjä avaa hakemiston FolderView:stä.

private void FolderView_BeforeExpand(object sender, System.Windows.Forms.TreeViewCancelEventArgs e) {
	try {
		TreeNode node = e.Node;
		string path = "";
 
		do  {
			path = node.Text + "\\" + path;
			node = node.Parent;
		} while (node != null);
 
		e.Node.Nodes.Clear();
 
		string[] dirs = Directory.GetDirectories(path);
		foreach (string dir in dirs) {
			string tmp = dir.Substring(dir.LastIndexOf("\\") + 1);
			if (tmp == "." || tmp == "..") {
				continue;
			}
 
			TreeNode childNode = new TreeNode(tmp);
			childNode.Nodes.Add(".");
			e.Node.Nodes.Add(childNode);
		}
 
		e.Cancel = e.Node.Nodes.Count == 0;
	}
	catch (Exception ex) {
		MessageBox.Show(ex.ToString());
	}
}

Aluksi käymme kaikki nodet läpi valitusta nodesta isäntään päin. Näin saamme hakemistopolun selville. Seuraavaksi tyhjennämme kaikki nodet valitusta nodesta alaspäin (lapsinodet). Näin saamme tuhottua myös sen turhan "." noden.

Seuraavaksi käymme jälleen foreach loopissa kaikki alihakemistot, jotka Directory.GetDirectories palauttaa. Valitettavasti GetDirectories palauttaa koko hakemistopolun, joten poistamme polusta alkuosan ja sijoitamme sen tmp muuttujaan. Jos palautettu tiedosto oli "." tai "..", emme lisää niitä puuhun. Tämän jälkeen teemme jälleen tutun noden lisäyksen puuhun ja teemme nodelle jälleen sen turhan "." lapsinoden. Sitten tarkastamme tuliko valitulle nodlle yhtään lapsinodea. Jos ei tullut, peruutamme noden avauksen, jolloinka se + merkki häviää puusta ilmoittaen käyttäjälle, että hakemistolla ei ole alihakemistoja.

Mene jälleen formin design näyttöön, valitse FolderView ja tuplaklikkaa eventtia AfterSelect. Nyt lisäämme koodin, joka päivittää tiedostonäkymän, kun käyttäjä on valinnut hakemiston FolderViewistä.

private void FolderView_AfterSelect(object sender, System.Windows.Forms.TreeViewEventArgs e) {
	try {
		TreeNode node = e.Node;
		string path = "";
 
		do  {
			path = node.Text + "\\" + path;
			node = node.Parent;
		} while (node != null);
 
		FileView.Items.Clear();
 
		string[] files = Directory.GetFiles(path);
		foreach (string file in files) {
			string tmp = file.Substring(file.LastIndexOf("\\") + 1);
			FileView.Items.Add(tmp);
		}
	}
	catch (Exception ex) {
		MessageBox.Show(ex.ToString());
	}
}

Alussa teemme jälleen saman, mitä hakemistojenkin kohdalla. Haemme FolderViewistä valitun noden isäntänodet ja saamme näin hakemistopolun selville. Koodissa tulee paljon toistoa tämän rutiinin kohdalta, joten tämä kannattaisi siirtää omaan metodiinsa. Tämä jätetään kuitenkin lukijan kotitehtäväksi. Seuraavaksi tyhjennämme FileView näytön ja lisäämme uudet tiedot näyttöön. Nyt onkin aika lisätä toimintoa tiedostoille.

Luo FileViewille eventti DoubleClick desing editorin kautta. Luomme nyt metodin, joka käynnistää tuplaklikatun tiedoston shellin kautta.

private void FileView_DoubleClick(object sender, System.EventArgs e) {
	try {
		if (FileView.SelectedItem != null) {
			TreeNode node = FolderView.SelectedNode;
			string path = (string)FileView.SelectedItem;
 
			do  {
				path = node.Text + "\\" + path;
				node = node.Parent;
			} while (node != null);
 
			Process proc = new Process();
			proc.StartInfo.FileName = path;
			proc.StartInfo.Verb = "open";
			proc.Start();
		}
	}
	catch (Exception ex) {
		MessageBox.Show(ex.ToString());
	}
}

Aluksi haemme taas polun ja tällä kertaa lisäämme siihen valitun tiedoston nimen. Sitten luomme Process olion ja annamme sille tiedoston polkuineen sekä käskyn avata tiedosto. Jos kaikki sujuu hyvin, ohjelmamme suorittaa nyt valitun tiedoston.

Tähän päättyy tutoriaalimme tältä kertaa.

Henkilökohtaiset työkalut