WPF - Pääteohjaus 6
Tee seuraavat tehtävät WPF-ohjelmaksi Visual Studiolla.
Suositeltavaa luettavaa: Introduction to WPF ja WPF Tutorial.net
- Aloita uusi projekti ja valitse tyypiksi WPF Application
- Tee autolaskuri eli lisää lomakkeelle painike ja laskukenttä. Säädä autolaskuri toimimaan myös näppäimistölä L-kirjaimesta. Huomannet, että WPF:ssä _ on sama kuin &-merkki Windows Formsissa.
- Lisää lomakkeen jokaiseen kulmaan label. Varmista, että labelit myös pysyvät kulmissa ikkunaa suurennettaessa. Kokeile miten toimivat DockPanel, StackPanel ja WrapPanel
- Liitä jokainen uusista labeleista seuraamaan autolaskuria eli näyttämään laskurin lukema. Tämä pitää onnistua
ilman ohjelmakoodia!
<Binding ElementName="labelLaskuri" Path="Content" />
Toinen vaihtoehto attribuuttina:
Text="{Binding ElementName=labelLaskuri, Path=Content}" - Varmista, että kaikki labelit toimivat.
- Lisää projektiisi oliomallinen (EDM) tietolähde. Käytä samaa reseptitietokantaa kuin edellisissä pääteohjauksissakin.
- Lisää ohjelmasi ikkunan DataContextiksi reseptitietokanta:
DataContext = new ohjaus5Entities().Resepti;
- Lisää lomakkeellesi combobox ja aseta sen tietolähteeksi reseptit
<ComboBox IsSynchronizedWithCurrentItem="True" ItemsSource="{Binding}" /> - Kokeile näkyykö reseptilistausta. Listaukseen pitäisi ilmestyä reseptiolioita. Joudut
vielä opettamaan reseptille miten sen pitää näkyä merkkijonona:
public partial class Resepti : EntityObject { public override string ToString() { return this.Nimi; } }EntityObject löytyy paikasta: System.Data.Objects.DataClasses
- Jos nyt reseptilistaus toimii niin lisää muutama TextBox näyttämään valittuna olevan reseptin tietoja (Nimi, Henkilomaara ja Kuvaus):
<TextBox Text="{Binding Path=Nimi}" />Sekä compobox että textbox osaavat käyttää ylemmällä tasolla määriteltyä DataContextia. IsSynchronizedWithCurrentItem pitää comboboxin synkronoituna valitun reseptin kanssa eli valinnan vaihtaminen comboboxissa vaikuttaa myös tietolähteessä juuri sillä hetkellä valittuna olevaan reseptiin ja täten heijastuu myös TextBoxeihin.
Aiheesta tarkemmin: WPF DataGrid Practical Examples
- Kokeile luoda omia tyylejä. Tee yhdellä tyylimäärityksellä kaikista lomakkeella olevista labeleista yhdenmuotoiset: aseta kaikkien fontiksi Times New Roman, fontin kooksi 22 ja taustaväriksi keltainen. Labelien määrityksiin ei tarvi eikä pidä koskea! Tyylien kirjoittaminen selitetään artikkeleissa A Guided Tour of WPF – Part 5 (Styles) ja WPF Styles and Control Templates
- Kirjoita oma erityistyyli autolaskurin labelia varten. Anna tälle tyylille tunnisteeksi "Laskuri" ja aseta autolaskurin label käyttämään juuri tätä tyyliä.
- Tee painike joka vaihtaa jonkun tietyn labelin tyyliksi saman mitä autolaskurilla
label.Style = (Style)FindResource("tunniste"); - Muuta edellisen labelin tyyliä siten, että labelin taustaväri muuttuu keltaiseksi jos hiiri viedään labelin päälle. Tämäkin onnistuu ilman yhtään koodiriviä käyttäen triggereitä.
- Sijoita lomakkeelle Canvas-elementti. Piirrä Canvaksen sisään viiva (Line) ja laatikko (Rectangle). Yritä saada piirto-objektien koko muuttumaan canvas-elementin koon mukana. Huomaathan, että OnPaint-metodia et tarvitse WPF:ssä.
- Windows Formsista tuttu Timer puuttuu WPF:stä. Aseta artikkelin Timer in WPF avulla
koko lomakkeesi sisältö kiertymään hitaasti ympäri. Aseta gridille aluksi sopiva rendertransform ja muuta sitä sitten
ohjelmallisesti:
<Grid.RenderTransform> <RotateTransform Angle="0" /> </Grid.RenderTransform>
Tee sitten sama käyttäen WPF-animaatiota.Esimerkki:
<Button.Triggers> <EventTrigger RoutedEvent="Button.Click"> <BeginStoryboard> <Storyboard> <DoubleAnimation Storyboard.TargetName="AnimButton" Storyboard.TargetProperty="Width" From="50.0" To="0.0" Duration="0:0:5" AutoReverse="True" RepeatBehavior="Forever" /> </Storyboard> </BeginStoryboard> </EventTrigger> </Button.Triggers> - Tee autolaskuri koostettuna komponenttina. Kokeile komponenttisi toimintaa
- Varmista, että komponenttisi skaalautuu järkevästi. Määritä komponenttisi painikkeelle ja laskurikentälle järkevä minimileveys ja minimikorkeus.
- Lisää autolaskurikomponenttiisi Laskuri DependencyPropertyna.
// nimeäminen tehtävä juuri seuraavalla tavalla public static readonly DependencyProperty LaskuriProperty = DependencyProperty.Register( "Laskuri", typeof(int), // propertyn tietotyyppi typeof(Autolaskuri), // luokka jossa property sijaitsee new FrameworkPropertyMetadata(0, // propertyn oletusarvo FrameworkPropertyMetadataOptions.AffectsRender, // vaikuttaa luokan ulkoasuun (textbox päivittyy) new PropertyChangedCallback(OnValueChanged), // kutsutaan propertyn arvon muuttumisen jälkeen new CoerceValueCallback(MuutaLaskuria))); // kutsutaan ennen propertyn arvon muutosta // seuraavat tehtävä juuri näin. Ei mitään tarkistuksien lisäämistä public int Laskuri { get { return (int)GetValue(LaskuriProperty); } set { SetValue(LaskuriProperty, value); } } // tätä kutsutaan ennen laskurin muuttamista ja voidaan tässä vaiheessa // tehdä tarkistuksia ja muuttaa laskuriin asetettavaa arvoa private static object MuutaLaskuria(DependencyObject element, object value) { int luku = (int)value; if (luku < 0) value = 0; return luku; } // Laskuria on muutettu. Päivitetään tieto myös textboxiin private static void OnValueChanged(DependencyObject obj, DependencyPropertyChangedEventArgs args) { Autolaskuri o = (Autolaskuri)obj; o.textBoxLaskuri.Text = (Convert.ToInt16(o.textBoxLaskuri.Text) + 1).ToString }Kokeile propertyn toimintaa Bindaamalla jokin tekstikenttä laskuriisi. - Lisää autolaskuriisi myös RouteEvent jolla muut voivat seurata milloin laskurin arvo muuttuu:
// esitellään ja rekisteröidään event public static readonly RoutedEvent ValueChangedEvent = EventManager.RegisterRoutedEvent( "ValueChanged", // tapahtuman nimi RoutingStrategy.Bubble, // toimintatapa typeof(RoutedPropertyChangedEventHandler<int>), //eventissä liikuteltavan tiedon tietotyyppi int typeof(Autolaskuri)); // luokka johon event lisätään // muutos edellätehtyyn funktioon private static void OnValueChanged(DependencyObject obj, DependencyPropertyChangedEventArgs args) { Autolaskuri o = (Autolaskuri)obj; o.textBoxLaskuri.Text = (Convert.ToInt16(o.textBoxLaskuri.Text) + 1).ToString // aiheutetaan routedevent RoutedPropertyChangedEventArgs<int> e = new RoutedPropertyChangedEventArgs<int>( (int)args.OldValue, (int)args.NewValue, ValueChangedEvent); o.OnValueChanged(e); } // pakolliset jotta luokkaan voidaan liittää käsittelijöitä tälle eventille public event RoutedPropertyChangedEventHandler<int> ValueChanged { add { AddHandler(ValueChangedEvent, value); } remove { RemoveHandler(ValueChangedEvent, value); } } // laukaisee varsinaisen eventin protected virtual void OnValueChanged(RoutedPropertyChangedEventArgs<int> args) { RaiseEvent(args); } - Kokeile miten RoutedEvent toimii.

Käyttäjien kommentit