1. UWP-GUI ja WPF-erot

WFP:n cs-koodi toimii UWP:ssä lähes sellaisenaan. Voidaan ottaa kaikki staattiset funktiot käyttöön.

1.1 GUIn luominen

Luodaan aluksi Designerilla hyvännäköinen UWP-GUI. Voimme käyttää lähes kaikkia WFP-tapahtumakäsittelijöitä.

GUIn koodi tässä vaiheessa

Ylläolevan koodin näkymä designerissa.
Ylläolevan koodin näkymä designerissa.

1.2 Erot WFP-koodiin

Seuraavaksi käydään läpi vain erot WPF-koodiin. Tällä sivulla ei kirjoiteta koko UWP-koodia.

TextBox-kontrollilla ei UWP:ssa ole Clear-funktiota, joten sen sijaan sijoitetaan tekstiksi tyhjää.

            textBoxKommentti.Text = "";

Uusia ikkunoita (Window) ei voida (ainakaan samalla lailla) luoda, eikä myöskään "vanhoja" sulkea. Palataan tähän myöhemmin, mutta esimerkiksi raportin näyttäminen tehdään erilailla.

1.2.1 Tiedostojen käsittely

Tiedostosta lukeminen tapahtuu hyvin erilaisesti UWP:ssä. Polkuja ei voida enää käyttää. Luodaan attribuuteiksi StorageFile-tyyppisiä tiedostoja ja niille StorageFolder.

        private Windows.Storage.StorageFolder tallennuskansio;
        private Windows.Storage.StorageFile projektitiedosto;
        private Windows.Storage.StorageFile aikatiedosto;
        private Windows.Storage.StorageFile nykprojtiedosto;

Tällaisten tiedostojen lukeminen tehdään asynkronisesti, jolloin vaarana on, että ohjelmakoodissa siirrytään eteenpäin liian aikaisin. Tämän estämiseksi käytetään await-komentoa, joka varmistaa, ettei koodissa siirrytä eteenpäin ennen kuin rivin suoritus on valmis.

        private async System.Threading.Tasks.Task LuoProjektitAsync()
        {
            tallennuskansio = Windows.Storage.ApplicationData.Current.LocalFolder;
            projektitiedosto = await tallennuskansio.CreateFileAsync("projektit.txt", 
                Windows.Storage.CreationCollisionOption.ReplaceExisting);
        }

MainPage-aliohjelmasta voidaan kutsua asynkronista Alusta-aliohjelmaa, jossa tehdään kaikki alustukset (jotka WPF-versiossa tehtiin MainWindow-aliohjelmassa).

        public MainPage()
        {
            Alusta();
        }
            ...
        private async void Alusta()
        {
            await LuoProjektitAsync();
            InitializeComponent();
                ...
        }

Valitettavasti nykyisten tiedostojen sorkkiminen on hankalaa, joten yksinkertaisuuden vuoksi kirjoitamme projektit koodiin. (Tämä voitaisiin oikeasti toteuttaa niin, että ohjelmassa voisi syöttää projektit.) Lisätään tiedoston luominen, lukeminen ja taulukkoon tallentaminen LuoProjektitAsync-aliohjelmaan.

            await Windows.Storage.FileIO.WriteTextAsync(projektitiedosto, 
                "ohjelmointikurssi\n" + "-demot\n" + ... + "-lukupiiri");
            string projString = await Windows.Storage.FileIO.ReadTextAsync(projektitiedosto);
            projektitKaikki = projString.Split('\n');

1.2.2 Pudotusvalikoiden tapahtumakäsittelijät koodissa

Lisätään vielä pudotusvalikoille tapahtumakäsittelijät Alusta-aliohjelman loppuun.

            comboBoxPaaprojektit.SelectionChanged += Paaprojektivalikko_SelectionChanged;
            comboBoxAliprojektit.SelectionChanged += Aliprojektivalikko_SelectionChanged;

Voisimme toteuttaa .xaml-koodissa vastaavan, mutta tällöin ominaisuus tulee käyttöön välittömästi ohjelman käynnistyessä, kun taas nyt toteuttamallamme tavalla asetamme tämän ominaisuuden vasta muiden alustusten jälkeen. Ilman tätä _SelectionChanged-aliohjelmat toteutettaisiin kesken koodin, kun pudotusvalikoiden valittua itemiä sörkitään.

Koko koodi tässä vaiheessa

2. Tiedostoihin tallentaminen

2.1 Projektien muistaminen

Luodaan/luetaan myös aika- ja nykyprojektitiedostot (OpenIfExists).

            aikatiedosto = await tallennuskansio.CreateFileAsync("ajat.txt", 
                Windows.Storage.CreationCollisionOption.OpenIfExists);
            nykprojtiedosto = await tallennuskansio.CreateFileAsync("nykproj.txt", 
                Windows.Storage.CreationCollisionOption.OpenIfExists);
            string nykprojString = await Windows.Storage.FileIO.ReadTextAsync(nykprojtiedosto);
            nykyisetProjektit = nykprojString.Split('\n');

Tätä varten on tietysti luotava uusi attribuutti nykyisetProjektit.

Asetetaan LuoValikko-aliohjelmassa pudotusvalikoihin nykyiset projektit.

            comboBoxPaaprojektit.SelectedItem = nykyisetProjektit[0];
            VaihdaPaaprojektia();
            comboBoxAliprojektit.SelectedItem = nykyisetProjektit[1];

Koska comboBoxPaaprojektit.SelectionChanged-ominaisuuutta ei olla vielä tässä vaiheessa koodia asetettu, on meidän lisättävä projektien asettamisten väliin käsin kutsu VaihdaPaaprojektia-aliohjelmaan, joka mm. hakee pääprojektin aliprojektit.

Lisätään vielä initiaalisen kaatumisen estämiseksi ennen yo. rivejä turvarivi, sillä ensimmäisellä ajokerralla tiedostossa ei ole kahta alkiota.

            if (nykyisetProjektit.Length < 2) return;

Samoin on syytä lisätä turvarivi myös VaihdaPaaprojektia-aliohjelman alkuun.

            if (comboBoxPaaprojektit.SelectedItem == null) return;

Kutsutaan VaihdaAliprojektia-aliohjelmasta uutta asynkronista tallennusaliohjelmaa TallennaNykyisetProjektitAsync. Huomaa, että käytetään rivinvaihtoon \n-merkkiä (char, engl. character).

        private void VaihdaAliprojektia()
        {
            if (comboBoxAliprojektit.SelectedItem == null) return;
            string valitutProjektit = comboBoxPaaprojektit.SelectedItem.ToString() +
                '\n' + comboBoxAliprojektit.SelectedItem.ToString();
            TallennaNykyisetProjektitAsync(valitutProjektit);
        }

Kirjoitetaan tässä aliohjelmassa nykyiset projektit tiedostossa olevan tekstin päälle.

        private async void TallennaNykyisetProjektitAsync(string valitutProjektit)
        {
            await Windows.Storage.FileIO.WriteTextAsync(nykprojtiedosto, valitutProjektit);
        }

Ohjelma muistaa nyt viimeksi käytetyn projektikokonaisuuden.

2.2 Aikatietojen tallentaminen

Lisätään staattiseen aliohjelmaan TallennaTiedot kutsu uuteen asynkroniseen aliohjelmaan TallennaTiedostoonAsync argumenttina tallenneteksti.

            TallennaTiedostoonAsync(tallenneteksti);

Tämä ei staattisesta aliohjelmasta ole tietenkään mahdollista, joten valitettavasti joudumme muuttamaan TallennaTiedot-aliohjelman metodiksi.

        public string TallennaTiedot(string paaprojekti, string aliprojekti, ...
        { 
            ...
        }

Lisätään tämä teksti tiedoston vanhan tekstin jatkoksi tässä uudessa aliohjelmassa.

        private async void TallennaTiedostoonAsync(string tallenneteksti)
        {
            await Windows.Storage.FileIO.AppendTextAsync(aikatiedosto, tallenneteksti);
        }

Koko koodi tässä vaiheessa

3. Raportin näyttäminen

3.1 Raportin avaaminen

Koska UWP toimii kaikilla Windows-alustoilla, ei valikkopalkin tekeminen olekaan kovin yksinkertaista.

Lisätään sen sijaan stackPanelNaytot-kontrollin sisään uusi painike Raportille.

            <Button x:Name="buttonRaportti" Content="Raportti" HorizontalAlignment="Center" 
                Margin="0,0,0,5" Click="Raportti_Click"/>

Koska uusien ikkunoimien luominen ei UWP:ssä ole kovin helppoa, tehdään raportti alueeksi nykyistä ikkunaa.

Luodaan aiempien alueiden ylepuolelle uusi alue, jonka sisällä on tekstialue ja Takaisin-painike.

        <Grid x:Name="gridRaportti" Margin="5,0">
            <Grid.RowDefinitions>
                <RowDefinition Height="1*"/>
                <RowDefinition Height="1*"/>
            </Grid.RowDefinitions>
            <Button Grid.Row="0" Content="Takaisin" HorizontalAlignment="Center" 
                Margin="0,5" Click="Takaisin_Click"/>
            <TextBox x:Name="textBoxRaportti" Grid.Row="1" TextWrapping="Wrap" 
                FontFamily="Courier New"/>
        </Grid>

Tekstialueen fontin tulee olla tasalevyinen ja TextWrapping päällä.

Lisätään gridRaportti vielä gridit-listaan, jotta voimme vaihtaa näkyvyysalueita myös tämän alueen osalta.

gridit.Add(gridRaportti);

Raportti-painiketta painaessa gridRaportti tulee näkyviin ja kaikki muu menee piiloon.

        private async void Raportti_Click(object sender, RoutedEventArgs e)
        {
            VaihdaNakyvyysalue(gridRaportti);
            stackPanelNaytot.Visibility = Visibility.Collapsed;
        }

Luetaan tässä aliohjelmassa vielä aikatiedosto ja kutsutaan Raportoi-aliohjelmaa textBoxRaportti-kentän tekstiksi.

            string ajatString = await FileIO.ReadTextAsync(aikatiedosto);
            string[] ajat = ajatString.Split('\n');
            textBoxRaportti.Text = Raportoi(projektitKaikki, ajat);

3.2 Raportin sulkeminen

Lisätään vielä näkvyyyden vaihto Takaisin-painikkeeseen.

        private void Takaisin_Click(object sender, RoutedEventArgs e)
        {
            VaihdaNakyvyysalue(gridAloitus);
            stackPanelNaytot.Visibility = Visibility.Visible;
        }

Nyt hienossa raportin näyttämisessä on pienoinen ongelma. Takaisin-painike johtaa aina aloitusnäkymään. Jos käyttäjä painaa ajanoton lopettamisen jälkeen Raportti-painiketta ennen Tallenna-painikkeen painallusta, aika menetetään, sillä näkymä ei palaudukaan takaisin lopetusnäkymään.

Estetään Raportti-painikkeen klikkaaminen lopetusnäkymään siirryttäessä.

        private void Lopeta_Click(object sender, RoutedEventArgs e)
        {
                ...
            buttonRaportti.IsEnabled = false;
        }

Painike täytyy tietenkin palautua mistä tahansa kolmesta painikkesta klikattaessa. Helpoin on tehdä tämä kaikille yhteisessä VaihdaNakyvyysalue-aliohjelmassa.

        private void VaihdaNakyvyysalue(Grid grid)
        {
                ...
            buttonRaportti.IsEnabled = true;
        }

Valmis koodi

These are the current permissions for this document; please modify if needed. You can always modify these permissions from the manage page.