Tehdään WPF-sovellus - 24 - Lisää ViewModeleita
- 5 minsInfra ei häiritse ViewModelien luontia
Olemme tehneet nyt suurimman osan taustatyöstä, jotta pääsisimme toteuttamaan näkymien taustalla olevia ViewModel-luokkia kätevästi huolehtimatta niitä ympäröivästä infrastruktuurista.
Emme voi kovin paljoa tehdä pääikkunan ViewModelin puolella ennen kuin meillä on navigoitavien näkymien ViewModelit käsissämme.
Aloitetaan siis lisäämällä InputViewModel
ja ResultViewModel
, jotka perivät ViewModel-kantaluokkamme.
InputViewModel
InputViewModel on pääikkunalla näytettävä painon ja pituuden syötekenttien näkymä. Tarvitsemme siis näitä syötekenttiä vastaavat propertyt tälle ViewModelille.
Määritellään ensin luokka uuteen tiedostoon:
using Kettunen.BMICalculator.WPFClient.MVVM;
namespace Kettunen.BMICalculator.WPFClient
{
public class InputViewModel : ViewModel
{
}
}
Lisätään tämän jälkeen backing fieldit ja itse property tähän tapaan sekä painolle että pituudelle:
private double _weight;
public double Weight
{
get => _weight;
set => SetProperty(ref _weight, value);
}
ViewModel
-kantaluokan SetProperty
-funktiota hyödyksi setterissä. Tee sama Height
-arvolle ja lopputuloksen pitäisi olla tämä:
using Kettunen.BMICalculator.WPFClient.MVVM;
namespace Kettunen.BMICalculator.WPFClient
{
public class InputViewModel : ViewModel
{
private double _weight;
public double Weight
{
get => _weight;
set => SetProperty(ref _weight, value);
}
private double _height;
public double Height
{
get => _height;
set => SetProperty(ref _height, value);
}
}
}
ResultViewModel
ResultViewModel ei paljoa vaadi, joten näytän sen vain tässä kokonaisuutena ilman höpinöitä:
using Kettunen.BMICalculator.WPFClient.MVVM;
namespace Kettunen.BMICalculator.WPFClient
{
public class ResultViewModel : ViewModel
{
private double _result;
public double Result
{
get => _result;
set => SetProperty(ref _result, value);
}
}
}
Viewien DataContextit kuntoon
Koska meillä on nyt käsissämme kahdelle näkymälle ViewModelit, niin käydään myös päivittämässä näiden näkymien d:DataContext
-arvot kohdilleen:
<UserControl ...
d:DataContext="{d:DesignInstance Type={x:Type local:InputViewModel}"
...
<UserControl ...
d:DataContext="{d:DesignInstance Type={x:Type local:ResultViewModel},
IsDesignTimeCreatable=True}"
...
IsDesignTimeCreatable=True
, jotta voimme kokeilla toista tapaa alustaa suunnittelunaikainen tieto näkymälle. Tuloksen bindaus ViewModelin propertyyn
Olemme aiemmin asettaneet tulosnäkymämme arvon oletuksena “123”. Jos laskurimme antaisi jokaiselle syötetylle arvolle saman tuloksen, olisi kyseessä vain aika huono laskuri.
Bindataan siis tuloksen tekstikenttä ViewModelin Result
-arvoon:
<TextBlock Grid.Row="1"
Text="{Binding Result}" />
Design-näkymämme arvo on vaan ehkä hieman ankeasti nyt “0”. Tälle täytyy tehdä jotain!
Design-arvon voi määrittää myös ViewModelin puolella
Aiemmin annoimme d:Text
-attribuutille arvon, joka näytettäisiin suunnittelun aikaisena tietona näkymällä (kts. InputView.xaml
).
Voimme kuitenkin toteuttaa tämän toisellakin tapaa: suunnittelunaikainen data on myös saatavilla ViewModelin kautta, koska Designer-näkymä alustaa ihan oikean instanssin ViewModelista latautuessaan, jos sen IsDesignTimeCreatable=True
.
Meidän olisi syytä kuitenkin varmistua jotenkin siitä, ettei Designer-näkymä yritä esimerkiksi käynnistää tietokantayhteyksiä, tai suorittaa jotain kauan kestäviä operaatioita ihan vain sen takia, että se yrittää vain ladata ViewModeliamme esittääkseen sen.
ViewModelille uusi property
Käydään lisäämässä ViewModel
-kantaluokallemme uusi property IsInDesignMode
. Tämän propertyn tarkoituksena on kertoa, että suoritetaanko koodia Designerin toimesta, vai ihan oikeasti sovellusta suorittamalla.
using System.Windows;
...
public abstract class ViewModel : INotifyPropertyChanged
{
public static bool IsInDesignMode => DesignerProperties.GetIsInDesignMode(new DependencyObject());
...
static
. Tämä tarkoittaa sitä, että kyseistä arvoa voi kysyä, vaikkei olisi alustanutkaan luokkaa new
-avainsanalla. Nyt voimme käydä lisäämässä ResultViewModelille
rakentajan, jossa pääsemme hyödyntämään uutta propertyamme:
public ResultViewModel()
{
if (IsInDesignMode)
{
Result = 123;
}
}
Kun olet kääntänyt ohjelman pitäisi Design-näkymässä näkyä antamasi arvo.
IsInDesignMode
-propertyn käyttäminen. Tässä muutamia tapoja, joilla tietoa voi esittää ilman ViewModel-tasolle menemistä. d:
-notaatiota XAML-puolella esimerkkidatan tuottamiseen aina kun se on vain mahdollista ja jättämällä IsDesignTimeCreatable
-arvon asettamatta d:DataContexti
:a määritettäessä. Seuraavaksi toteutetaan navigointi
Voimme seuraavassa osassa keskittyä toteuttamaan navigointia näiden näkymien välillä nyt kun työkalupakistamme löytyy sopiva määrä ViewModeleita ja Viewejä.