Brakującym elementem w przedstawionym przykładzie była implementacja zdarzeń jakie oferują nam kontrolki.
Z pomocą przychodzi nam wzorzec projektowy Command, który doczekał się swojej implenetacji w Silverlight 4.
Ogólna koncepcja działania polega na tym by udostępnić możliwość obsługi zdarzeń w ViewModel’u. W obecnej chwili zaimplementowane są tylko zdarzenia Click dla kontrolek będących implementacją/rozszerzeniem klasy ButtonBase oraz kontrolki HyperLink. Ograniczenia te jednak można przekroczyć poprzez własną implementację tego wzorca.
By wykorzystać tę nową funkcjonalność należy stworzyć klasę dziedziczącą po interfejsie ICommand (namespace System.Windows.Input)
namespace System.Windows.Input { public interface ICommand { bool CanExecute(object parameter); void Execute(object parameter); event EventHandler CanExecuteChanged; } }
CanExecute – metoda określająca status czy podpięta komenda może być wykonana,
Execute – komenda wywoływana w wyniku wywołania zdarzenia (np. wspomniany Click),
CanExecuteChanged – zdarzenie wywoływane w momencie zmiany statusu wywołania komency. Mechanizm bindujący kod XAML podpina się do tego zdarzenia tak więc możecie zauważyć dziwną zależność w postaci : nie podpinacie nic do zdarzenia, a jednak metody Execute oraz CanExecute oddziaływują na siebie.
Poniżej przedstawiam moją własną implementację wykorzystania wzorca Command.
public class MyCommand : ICommand { private readonly Predicate<object> canExecute; private readonly Action<object> executeAction; public MyCommand(Action<object> executeAction, Predicate<object> canExecute) { this.canExecute = canExecute; this.executeAction = executeAction; } public bool CanExecute(object parameter) { if (canExecute != null) return canExecute(parameter); return true; } public void Execute(object parameter) { if (executeAction != null) executeAction(parameter); } public event EventHandler CanExecuteChanged; }
Klasa implemencująca interfejs ICommand korzysta z :
- delegatu Action<object> pozwalającego mi na oddelegowanie wykonania komendy do własnej implementacji metody Execute znajdującej się w ViewModel,
- delegatu Predicate<object> pozwalającego na oddelegowanie sprawdzenia testu możliwości wykonania komendy (CanExecute) do własnej implementacji metody znajdującej się w ViewModel.
Poniżej znajduje się część klasy ViewModel wykorzystującej powyższą komendę MyCommand
public class MyViewModel : INotifyPropertyChanged { private readonly MyModel myModel; public MyViewModel() { myModel = new MyModel(); ButtonCommandClick = new MyCommand(ButtonClickExecute, CanExecuteButtonClick); } private bool CanExecuteButtonClick(object obj) { if (!string.IsNullOrEmpty(Nickname) && Nickname == "Lukas") return false; return true; } private void ButtonClickExecute(object obj) { Description = String.Format("Witaj {0} ! To jest implementacja interfejsu ICommand", Nickname); } public string Nickname { get { return myModel.NickName ?? string.Empty; } set { if (myModel.ValidateNickName(value)) { myModel.NickName = value; FirePropertyChanged("Nickname"); } } } public ICommand ButtonCommandClick { get; set; }
By dopełnić dzieła wystarczy tylko zbindować właściwość Command klasy Button z właściwością ButtonCommandClick znajdującą się w naszy ViewModel’u.
<Button Content="Say Hello!" Command="{Binding Source={StaticResource myViewModel}, Path=ButtonCommandClick}" />
Powyższy przykład jest najprostszą postacią wykorzystania możliwości jakie daje nam wzorzezc Command. Pozwala on jednak na postawienie pierwszych kroków przy zaznajamianiu się z możliwościami MVVM.
Przykładową aplikację możecie pobrać TUTAJ
Duuuzy plus, jestes jedna z pierwszych osob ktore implemntujac beznadziejnie prosty interfejs ICommand nie pisza/mowia "dzieki JoshSmith" czy "za zgodza Josh Smith" publikuje implementacje ICommand.
OdpowiedzUsuńBo to dla mnie porazka jest na tych wszystkich blogach. Tak jakby implemntacja ICommand byla "super" skomplikowana.
Dzięki
OdpowiedzUsuńPostaram się częściej zamieszczać własne implementacje (również bardziej skomplikowanych rzeczy).
Pozdrawiam