Tehdään WPF-sovellus - 23 - Komennon toteutus

- 3 mins

Komennon toteuttaminen yhdellä luokalla

ICommand-rajapinnan toteuttavan luokan property voidaan bindata Button-elementin Command-attribuuttiin. Meillä ei vain kylläkään ole yhtäkään toteutusta vielä ICommand-rajapinnalle.. Tehdään tähän muutos!

Aloitetaan lisäämällä MVVM-kansioon uusi luokka DelegateCommand ja määrätään se toteuttamaan ICommand-rajapinta:

using System;
using System.Windows.Input;

namespace Kettunen.BMICalculator.WPFClient.MVVM
{
    public class DelegateCommand : ICommand
    {
        public event EventHandler CanExecuteChanged;

        public bool CanExecute(object parameter)
        {
            throw new NotImplementedException();
        }

        public void Execute(object parameter)
        {
            throw new NotImplementedException();
        }
    }
}
DelegateCommand.cs

Komento koostuu yksinkertaisimmillaan näistä kolmesta rajapinnan määrittelemästä komponentista.

Toteutetaan oma komentomme hyvin yleiskäyttöiseksi, jotta emme joutuisi tekemään aina uutta tyyppiä uudelle komennolle esim. CalculateCommand, BackCommand jne..

Rakentajan toteuttaminen

Aloitetaan rakentajasta. Komennon tarkoitus on siis suorittaa toiminto ja olla tietoinen siitä, että voiko toimintoa ylipäätään suorittaa kyseisessä ohjelman tilassa.

Näkymä antaa komennolle parametriksi null tai object-tyyppisen instanssin kutsuessaan komentoa. Määrittelemme näkymän puolella annettavan parametrin myöhemmin.

Näiden tietojen perusteella voimme nikkaroida rakentajan kasaan:

public class DelegateCommand : ICommand
{
    private readonly Action<object> _execute;
    private readonly Predicate<object> _canExecute;

    // ...

    public DelegateCommand(Action<object> execute, Predicate<object> canExecute)
    {
        _execute = execute;
        _canExecute = canExecute;
    }
}
DelegateCommand.cs

CanExecute ja Execute

Näiden lisäysten jälkeen CanExecuten ja Executen toteuttaminen on hyvin suoraviivaista. Kutsutaan niissä vain juuri lisäämiämme _canExecute- ja _execute-toimintoja.

public bool CanExecute(object parameter) => _canExecute(parameter);

public void Execute(object parameter) => _execute(parameter);
DelegateCommand.cs

CanExecuteChanged

CanExecuteChanged-tapahtuman voimme toteuttaa käyttämällä CommandManageria hyödyksi:

public event EventHandler CanExecuteChanged
{
    add { CommandManager.RequerySuggested += value; }
    remove { CommandManager.RequerySuggested -= value; }
}
DelegateCommand.cs

Ja mitäs ihmettä. Sanoisin, että se oli siinä! 💪

Mietteitä tästä kaikesta

Sinänsä tuntuu erikoiselta, ettei WPF:n kirjastoissa ole mukana oletustoteutusta jo valmiiksi ICommand- tai INotifyPropertyChanged-rajapinnoille. Väittäisin, että kuitenkin suurin osa WPF-sovelluksista nojaa juurikin näiden rajapintojen onnistuneisiin toteutuksiin.

Toisaalta toimiviksi todettuja MVVM-paketteja on runsaasti mistä valita, joten ehkä oletustoteutusta ei ole katsottu tarpeelliseksi.

Tähän väliin voisi melkeinpä suositella Tim Coreyn läpikäyntiä eri MVVM-frameworkeista (video).

Seuraavassa osassa luodaan Input- ja Result-näkymille omat ViewModelinsa. Siinä puuhassa päästäänkin käyttämään ViewModel.SetProperty-funktiota tarkoituksenmukaisella tavallaan!

Anssi Kettunen

Anssi Kettunen

Ohjelmistokehittäjä suorittamassa tehtävää 🦊

rss facebook twitter github gitlab youtube mail spotify lastfm instagram linkedin google google-plus pinterest medium vimeo stackoverflow reddit quora quora