MVVM Light Toolkit Przewodnik krok po kroku

Podobne dokumenty
MVVM Light Toolkit. Julita Borkowska

Rozwój aplikacji modułowych Paweł Brudnicki. Dodanie modułu

Przewodnik krok po kroku:

xmlns:prism= c. <ContentControl prism:regionmanager.regionname="mainregion" />

Programowanie obiektowe

- Narzędzie Windows Forms. - Przykładowe aplikacje. Wyższa Metody Szkoła programowania Techniczno Ekonomiczna 1 w Świdnicy

Instrukcja laboratoryjna nr.4

Instrukcja laboratoryjna cz.6

ASP.NET MVC. Podstawy. Zaawansowane programowanie internetowe Instrukcja nr 3

Instrukcja laboratoryjna cz.3

Programowanie obiektowe i zdarzeniowe wykład 1 Wprowadzenie do programowania zdarzeniowego

Logger. Następnie w klasie Bootstrapper muimy zarejestrować nasz nowy logger:

WYKONANIE APLIKACJI OKIENKOWEJ OBLICZAJĄCEJ SUMĘ DWÓCH LICZB W ŚRODOWISKU PROGRAMISTYCZNYM. NetBeans. Wykonał: Jacek Ventzke informatyka sem.

Wybieramy File->New->Project Wybieramy aplikację MFC->MFC Application jak na rysunku poniżej:

Programowanie obiektowe i zdarzeniowe wykład 4 Kompozycja, kolekcje, wiązanie danych

Informatyka II. Laboratorium Aplikacja okienkowa

Microsoft.NET: LINQ to SQL, ASP.NET AJAX

Politechnika Gdańska Katedra Optoelektroniki i Systemów Elektronicznych

1 LINQ. Zaawansowane programowanie internetowe Instrukcja nr 1

Aplikacje WWW - laboratorium

Wykład 4 Delegat (delegate), właściwości indeksowane, zdarzenie (event) Zofia Kruczkiewicz

Budowa aplikacji w technologii.net wykład 7 konwersja, walidacja, szablony, widoki

Rys. 3. Kod elementów na stronie po dodaniu kontrolek podstawowych.

Politechnika Poznańska Wydział Budowy Maszyn i Zarządzania

Ćwiczenie 1. Kolejki IBM Message Queue (MQ)

Laboratorium programowania urządzeń mobilnych

Rozpoczynając wywód na temat MVVM należy najpierw zadań sobie kilka podstawowych pytań na temat MVVM jako wzorca projektowego :

MVVM i XAML w Visual Studio 2015 / Jacek Matulewski. Gliwice, cop Spis treści

Programowanie zaawansowane

Programownie w technologii.net wykład 6 Element Binding i Data Binding

PHP 5 język obiektowy

Zawartość. Wstęp. Moduł Rozbiórki. Wstęp Instalacja Konfiguracja Uruchomienie i praca z raportem... 6

Przykładowa dostępna aplikacja w Visual Studio - krok po kroku

Instrukcja laboratoryjna cz.4

Projektowanie aplikacji internetowych laboratorium

Rozdział 3. Zapisywanie stanu aplikacji w ustawieniach lokalnych

Laboratorium 7 Blog: dodawanie i edycja wpisów

Klasy i obiekty cz II

JAVA W SUPER EXPRESOWEJ PIGUŁCE

Wprowadzenie do projektu QualitySpy

Utworzenie aplikacji mobilnej Po uruchomieniu Visual Studio pokazuje się ekran powitalny. Po lewej stronie odnośniki do otworzenia lub stworzenia

Funkcje i instrukcje języka JavaScript

Wykład 5 Okna MDI i SDI, dziedziczenie

Makropolecenia w PowerPoint Spis treści

Microsoft.NET: ASP.NET MVC + Entity Framework (Code First)

Zaawansowane aplikacje internetowe - laboratorium

Ćwiczenia 9 - Swing - część 1

1. Wprowadzenie do WPF i XAML. Tworzenie interfejsu użytkownika.

Dodanie nowej formy do projektu polega na:

Programowanie obiektowe

PWSG Ćwiczenia 12. Wszystkie ukończone zadania należy wysłać na adres: lub

Instrukcja tworzenia aplikacji bazodanowej opartej o technologię Oracle i platformę.net

C++ - przeciążanie operatorów. C++ - przeciążanie operatorów. C++ - przeciążanie operatorów. C++ - przeciążanie operatorów

KS-ZSA. Mechanizm aktualizacji kartotek lokalnych w aptece na podstawie zmian w kartotece CKT. Data aktualizacji:

Proxy (pełnomocnik) Cel: Zastosowanie: Dostarczyć zamiennik pewnego obiektu, pozwalający kontrolować dostęp do niego.

KLASA UCZEN Uczen imię, nazwisko, średnia konstruktor konstruktor Ustaw Wyswietl Lepszy Promowany

Programowanie obiektowe i zdarzeniowe

KLASA UCZEN Uczen imię, nazwisko, średnia konstruktor konstruktor Ustaw Wyswietl Lepszy Promowany

Zaawansowane aplikacje WWW - laboratorium

2. W oknie dialogowym Choose Toolbox Items w zakładce.net Framework Components naciskamy przycisk Browse...

Ciekawym rozwiązaniem służącym do obsługi zdarzeń dla kilku przycisków w ramach jednej aktywności może być następujący kod:

Zdarzenia i polecenia

Instrukcja 10 Laboratorium 13 Testy akceptacyjne z wykorzystaniem narzędzia FitNesse

Aplikacje w środowisku Java

Builder (budowniczy) Cel: Przykład:

5 AS SP.NET MVC. Walidacja danych. Zaawansowane programowanie internetowe Instrukcja nr 5

Laboratorium 1. Wzorce oprogramowania lab1, Zofia Kruczkiewicz

akademia androida Składowanie danych część VI

Instrukcja implementacji sterownika wirtualnego portu szeregowego dla systemu Android. Opracowanie: Elzab Soft sp. z o.o.

Zaawansowane aplikacje internetowe - laboratorium Web Services (część 1).

Aplikacje RMI

Leszek Stasiak Zastosowanie technologii LINQ w

Techniki programowania INP001002Wl rok akademicki 2018/19 semestr letni. Wykład 3. Karol Tarnowski A-1 p.

Korporacja Kurierska

Programowanie Obiektowe GUI

TEMAT : KLASY DZIEDZICZENIE

Programowanie obiektowe

Programowanie obiektowe

Programowanie wielowarstwowe i komponentowe

1. Które składowe klasa posiada zawsze, niezależnie od tego czy je zdefiniujemy, czy nie?

Instrukcja laboratoryjna cz.3

Instalowanie VHOPE i plików biblioteki VHOPE

autor poradnika - KS Jak zamieszczać i edytować artykuły na szkolnej stronie internetowej

Metody Metody, parametry, zwracanie wartości

Wprowadzenie do Doctrine ORM

Programowanie w środowisku graficznym GUI

D:\DYDAKTYKA\ZAI_BIS\_Ćwiczenia_wzorce\04\04_poprawiony.doc 2009-lis-23, 17:44

Aby nadać jej pożądaną postać należy w pliku Window1.xaml stworzyć definicję swojego stylu modyfikując ręcznie postać zapisu XAML:

Omówienie wzorców wykorzystywanych w Prism 5.0. Dominika Różycka

Dokumentacja panelu Klienta

Zdarzenia Zdarzenia onload i onunload

Obiekt klasy jest definiowany poprzez jej składniki. Składnikami są różne zmienne oraz funkcje. Składniki opisują rzeczywisty stan obiektu.

Zad.30. Czy można utworzyć klasę, która implementuje oba interfejsy?

Kompilacja javac prog.java powoduje wyprodukowanie kilku plików o rozszerzeniu.class, m.in. Main.class wykonanie: java Main

Platforma.NET laboratorium 4 Aktualizacja: 15/11/2013. Visual Basic.NET dostęp do bazy danych. Baza Microsoft SQL Server Compact

A Zasady współpracy. Ocena rozwiązań punktów punktów punktów punktów punktów

POLITECHNIKA POZNAŃSKA. Oprogramowanie dla telefonów z systemem Windows Phone 8 obsługujących technologię NFC do sprawdzania listy obecności.

Informatyka I. Klasy i obiekty. Podstawy programowania obiektowego. dr inż. Andrzej Czerepicki. Politechnika Warszawska Wydział Transportu 2018

Transkrypt:

Julita Borkowska 242817 MVVM Light Toolkit Przewodnik krok po kroku W celu lepszego zrozumienia elementów MVVM Light Toolkit przedstawionych w prezentacji, zostanie poniżej krok po kroku napisany program losujący sekretną liczbę, której odgadnięcie będzie zadaniem dla użytkownika. Zaczynamy od instalacji dodatku: Otwieramy Visual Studio, wybieramy Tools -> Extensions&Updates -> Online -> wpisujemy MVVM Light Toolkit i pobieramy, a następnie instalujemy. Następnie tworzymy nowy projekt i wybieramy MVVMLight (WPF451). Po stworzeniu projektu mamy już wygenerowane dwie klasy: MainViewModel.cs oraz ViewModelLocator.cs oraz pliki XAML: App.xaml i MainWindow.xaml. Klasa MainViewModel odpowiada za przechowywanie danych i odpowiednie reagowanie na zachowania użytkownika. Dodaję właściwość: - SecretNumber (typu int) reprezentuje ona liczbę, która należy odgadnąć; - Suggestion (typu string) - w niej zapisywane będą sugestie dotyczące podanej przez użytkownika liczby; - IsInProgress (typu bool) określa, czy użytkownik jest w danej chwili w trakcie zgadywania; - IsSolved (typu bool) określa, czy sekretna liczba została odgadnięta; Właściwości IsInProgress oraz IsSolved posłużą do pokazywania i ukrywania odpowiednich komunikatów).

We wszystkich powyższych podczas ustawiania wartości zostanie wywołana funkcja RaisePropertyChanged() z klasy bazowej (ViewModelBase), która opakowuje funkcjonalność interfejsu INotifyPropertyChanged. Interfejs ten ma zadanie informować klienta, że wartość właściwości (obiektu) uległa zmianie. Dzięki temu możemy korzystać z DataBindingu: przy każdej zmianie wartości zmiennej (zarówno w kodzie jak i przez użytkownika), jej wartość będzie na bieżąco aktualizowana. Aby oszczędzić sobie konieczności każdorazowego wpisywania powtarzalnego kodu, najlepiej jest skorzystać ze snippetów (czyli właśnie takich gotowych fragmentów kodu). W celu ich zastosowania należy w nowej linii wpisać mvvminpc, a następnie nacisnąć TAB pojawi się pożądany fragment kodu - konieczne jest już tylko podanie nazwy. #region SecretNumber Property public const string SecretNumberPropertyName = "SecretNumber"; private int _secretnumber = 0; public int SecretNumber return _secretnumber; set if (_secretnumber == value) return; _secretnumber = value; RaisePropertyChanged(SecretNumberPropertyName); #region Suggestion public const string SuggestionPropertyName = "Suggestion"; private string _suggestion = ""; public string Suggestion return _suggestion; set if (_suggestion == value) return; _suggestion = value; RaisePropertyChanged(SuggestionPropertyName);

#region IsInProgress Property public const string IsInProgressPropertyName = "IsInProgress"; private bool _isinprogress = false; public bool IsInProgress return _isinprogress; set if (_isinprogress == value) return; _isinprogress = value; RaisePropertyChanged(IsInProgressPropertyName); #region IsSolved Property public const string IsSolvedPropertyName = "IsSolved"; private bool _issolved = false; public bool IsSolved return _issolved; set if (_issolved == value) return; _issolved = value; RaisePropertyChanged(IsSolvedPropertyName); Tworzenie komend Zostaną teraz stworzone dwie komendy: - Start mająca za zadanie wylosować nową liczbę do odgadnięcia oraz stawienie właściwości określających stan zabawy na odpowiednie wartości logiczne; - CheckGuess mającą za zadanie sprawdzenie, czy podana przez użytkownika liczba jest prawidłowa oraz ewentualne podanie wskazówek, jeśli nie. Za reprezentowanie komend w MVVM Light Toolkit odpowiada klasa RelayCommand. Opakowuje ona interfejs ICommand, dając jednocześnie wygodny sposób na tworzenie nowych komend (nie

trzeba więc zagłębiać się w ich implementację). Istnieje również generyczna wersja RelayCommand, która pozwala na przekazywanie parametru do komendy. Przy tworzeniu kodu dla komendy Start możemy skorzystać ze snippetu mvvmrelay, a dla komendy CheckGuess mvvmrelaygeneric. #region Start private RelayCommand _startcommand; public RelayCommand Start if (_startcommand == null) _startcommand = new RelayCommand( () => SecretNumber = rand.next(10) + 1; IsSolved = false; IsInProgress = true; Suggestion = ""; ); return _startcommand; #region CheckGuess Command private RelayCommand<int> _checkguess; public RelayCommand<int> CheckGuess if(_checkguess == null) _checkguess = new RelayCommand<int>( x => if (x == _secretnumber) IsInProgress = false; IsSolved = true; else if (x < _secretnumber) Suggestion = "Liczba jest za mala."; else if (x > _secretnumber) Suggestion = "Liczba jest za duza."; ); return _checkguess; Interfejs użytkownika Aby możliwe było zgadywanie liczby, podawanie wskazówek oraz wyniku zgadywania stworzono interfejs widoczny na poniższym obrazku:

Generuje go poniższy kod XAML, umieszczony w pliku MainWindow.xaml: <Window x:class="projekt05.mainwindow" xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation" xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml" xmlns:d="http://schemas.microsoft.com/expression/blend/2008" xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006" xmlns:local="clr-namespace:projekt05" xmlns:ignore="http://www.ignore.com" mc:ignorable="d ignore" Height="300" Width="300" Title="MVVM Light Application" DataContext="Binding Main, Source=StaticResource Locator"> <Window.Resources> <BooleanToVisibilityConverter x:key="booleantovisibilityconverter"/> <local:stringtointconverter x:key="stringtointconverter"/> </Window.Resources> <StackPanel> <StackPanel x:name="spsecret" Orientation="Horizontal" Height="16" Visibility="Binding IsSolved, Converter=StaticResource BooleanToVisibilityConverter, Mode=OneWay"> <TextBlock Height="16" TextWrapping="Wrap" Text="Gratulacje! Sekretna liczba to: " /> <TextBlock x:name="txblsecret" Height="16" TextAlignment="Center" Margin="20,0,0,0" TextWrapping="Wrap" Text="Binding SecretNumber"/> <Button x:name="btnstart" Content="Start" Margin="0,10,0,0" Command="Binding Start, Mode=Default"/> <StackPanel x:name="spguess" Visibility="Binding IsInProgress, Converter=StaticResource BooleanToVisibilityConverter, Mode=OneWay"> <StackPanel Margin="0,10,0,0" Orientation="Horizontal"> <TextBlock Margin="8,0,0,0" TextWrapping="Wrap" Text="Podaj liczbę: " /> <TextBox x:name="txbuserguess" Height="24" TextAlignment="Center" Margin="25,0,0,0" TextWrapping="Wrap" Text="0" Width="50" HorizontalAlignment="Center" VerticalAlignment="Center"/>

<Button x:name="btncheck" Content="Sprawdź" Margin="0,10,0,0" Command="Binding CheckGuess" CommandParameter="Binding Text, Converter=StaticResource StringToIntConverter, ElementName=txbUserGuess"/> <TextBlock x:name="txblsuggestion" Margin="0,15,0,0" TextWrapping="Wrap" TextAlignment="Center" Text="Binding Suggestion"/> </Window> Podczas analizy powyższego kodu szczególną uwagę należy zwrócić na linijki, w których pojawia się słowo Binding. Dotyczy ono bowiem wspomnianej na początku tego opracowania możliwości DataBindingu, czyli tworzenia odpowiednich powiązań między widokiem i obiektem ViewModel. Jeśli chodzi o wiązanie właściwości lub komend, zastosowanie DataBinding jest bardzo proste: <Button x:name="btnstart" Content="Start" Command="Binding Start"/> Podobnie jak dla przycisku Start rozpoczynającego grę wygląda to dla pól tekstowych txblsecret oraz txblsuggestion, które są powiązane z właściwościami SecretNumber oraz Suggestion. Powiązanie jest nieco trudniejsze w przypadku przycisku, którym użytkownik sprawdza, czy odgadł sekretną liczbę: <Button x:name="btncheck" Content="Sprawdź" Command="Binding CheckGuess" CommandParameter="Binding Text, Converter=StaticResource StringToIntConverter, ElementName=txbUserGuess"/> Jak widzimy powyżej, w chwili naciśnięcia przycisku, Binding ustawia wykonywaną komendę na CheckGuess i podaje właściwość Text pola tekstowego txbuserguess jako jej parametr. Problemem jest jednak to, iż właściwość Text jest typu string, a komenda CheckGuess przyjmuje jako parametr obiekt typu int. Konieczna jest więc konwersja pomiędzy oba typami. Stworzono do tego celu obiekt StringToIntConverter dokonujący zmiany typów w obie strony. Dziedziczy on po interfejsie IValueConverter i implementuje jego dwie metody: Convert oraz ConvertBack. [ValueConversion(typeof(string), typeof(int))] public class StringToIntConverter : IValueConverter #region IValueConverter Members public object Convert(object value, Type tartype, object parameter, System.Globalization.CultureInfo culture) string str = value.tostring(); if (string.isnullorempty(str)) return 0; else try int result = 0; int.tryparse(str, out result); return result; catch (ArgumentException)

return 0; public object ConvertBack(object value, Type tartype, object parameter, System.Globalization.CultureInfo culture) return value.tostring(); Aby móc korzystać z nowo stworzonego konwertera, dodajemy go jako zasób obecnego widoku: <Window.Resources> <local:stringtointconverter x:key="stringtointconverter"/> </Window.Resources> Aby użytkownik nie dowiedział się jaka jest nasza sekretna liczba, należy prawidłowo ukryć oba panele. W tym celu należy powiązać ich właściwości Visibility z odpowiednimi właściwościami obiektu ViewModel: IsInProgress oraz IsSolved: <StackPanel x:name="spsecret" Visibility="Binding IsSolved, Converter=StaticResource BooleanToVisibilityConverter, Mode=OneWay"> <StackPanel x:name="spguess" Visibility="Binding IsInProgress, Converter=StaticResource BooleanToVisibilityConverter, Mode=OneWay"> Wykorzystany w powyższych fragmentach kodu konwerter BooleanToVisibilityConverter jest dostępny domyślnie, trzeba tylko dodać go jako zasób do obecnego widoku, podobnie jak uczyniono to z konwerterem StringToIntConverter. EventToCommand W kontrolkach WPF a komendy podpinane są domyślnie do jednego z góry przewidzianego zdarzenia, np. dla przycisku jest to odpowiednik onclick. Nie ma możliwości podłączenia komendy do innych zdarzeń. Dzięki MVVM Light Toolkit, istnieje możliwość podłączenia komend z obiektu ViewModel do dowolnych zdarzeń kontrolki bez angażowania do tego jakiegokolwiek Code Behind wszystko pozostaje więc w zgodzie z założeniami MVVM. <Window x:class="projekt05.mainwindow" xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation" xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml" xmlns:d="http://schemas.microsoft.com/expression/blend/2008" xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006" xmlns:vm="clr-namespace:projekt05" xmlns:i="http://schemas.microsoft.com/expression/2010/interactivity" xmlns:galasoft_mvvmlight_command="http://www.galasoft.ch/mvvmlight" xmlns:ignore="http://www.ignore.com" mc:ignorable="d ignore" Height="300" Width="300" Title="MVVM Light Application" DataContext="Binding Main, Source=StaticResource Locator"> <Window.Resources> <BooleanToVisibilityConverter x:key="booleantovisibilityconverter"/> <vm:stringtointconverter x:key="stringtointconverter"/>

</Window.Resources> <StackPanel> <StackPanel x:name="spsecret" Orientation="Horizontal" Height="16" Visibility="Binding IsSolved, Converter=StaticResource BooleanToVisibilityConverter, Mode=OneWay"> <TextBlock Height="16" TextWrapping="Wrap" Text="Gratulacje! Sekretna liczba to: " /> <TextBlock x:name="txblsecret" Height="16" TextAlignment="Center" Margin="20,0,0,0" TextWrapping="Wrap" Text="Binding SecretNumber"/> <Button x:name="btnstart" Content="Start" Margin="0,10,0,0" Command="Binding Start, Mode=Default"/> <StackPanel x:name="spguess" Visibility="Binding IsInProgress, Converter=StaticResource BooleanToVisibilityConverter, Mode=OneWay"> <StackPanel Margin="0,10,0,0" Orientation="Horizontal"> <TextBlock Margin="8,0,0,0" TextWrapping="Wrap" Text="Podaj liczbę: " /> <TextBox x:name="txbuserguess" Height="24" TextAlignment="Center" Margin="25,0,0,0" TextWrapping="Wrap" Text="0" Width="50" HorizontalAlignment="Center" VerticalAlignment="Center"> <i:interaction.triggers> <i:eventtrigger EventName="LostFocus"> <GalaSoft_MvvmLight_Command:EventToCommand Command="Binding CheckGuess, Mode=Default" CommandParameter="Binding Text, Converter=StaticResource StringToIntConverter, ElementName=txbUserGuess"/> </i:eventtrigger> </i:interaction.triggers> </TextBox> <Button x:name="btncheck" Content="Sprawdź" Margin="0,10,0,0" Command="Binding CheckGuess" CommandParameter="Binding Text, Converter=StaticResource StringToIntConverter, ElementName=txbUserGuess"/> <TextBlock x:name="txblsuggestion" Margin="0,15,0,0" TextWrapping="Wrap" TextAlignment="Center" Text="Binding Suggestion"/> </Window> W przytoczonej powyżej zawartości pliku MainWindow.xaml zaznaczono na szaro dodane fragmenty. W przykładzie do zdarzenia LostFocus podpinane jest sprawdzenie, czy podana przez użytkownika liczba jest wylosowanym sekretnym numerem umożliwia to sprawdzanie liczby zarówno za pomocą przycisku Sprawdź, jak i kliknięcia TAB na klawiaturze. Do istniejącego TextBoxa odpowiedzialnego za wprowadzanie przez użytkownika liczby podpinamy nowy event trigger. Jest to trigger reagujący na zajście zdarzenia LostFocus za pomocą jednego znacznika możemy podpiąć komendę do tego triggera (w sposób w jaki wcześniej podpięliśmy ją do przycisku). Messenger Z założenia obiekt Messenger został dodany do MVVM Light Toolkit jako narzędzie do wszechstronnej komunikacji i to nie tylko pomiędzy obiektami ViewModel, ale między dowolnymi klasami. Idea opiera się na statycznym obiekcie Messenger, który udostępnia mechanizmy do wysyłania komunikatów oraz rejestrowania akcji reagujących na konkretne komunikaty.

Celem zademonstrowania działania obiektu Messenger, stworzony zostanie nowy obiekt ViewModel, który będzie panelem opcji programu, posiadającym jednak tylko jedną opcję mianowicie wybór maksymalnego zakresu wartości, z jakiego można wylosować sekretną liczbę. Po zatwierdzeniu zmian zaktualizowany zostanie maksymalny zakres liczb, a dzięki DataBinding informacja o aktualnym maksymalnym zakresie zostanie odświeżona. Na początek należy dodać w projekcie nowy folder View i stworzyć w nim nowy interfejs użytkownika OptionsView.xaml (klikamy na projekcie prawym klawiszem i wybieramy Add -> User control): <UserControl x:class="projekt05.view.optionsview" xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation" xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml" xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006" xmlns:d="http://schemas.microsoft.com/expression/blend/2008" mc:ignorable="d" xmlns:local="clr-namespace:projekt05" d:designheight="300" d:designwidth="300"> <UserControl.Resources> <local:stringtointconverter x:key="stringtointconverter"/> </UserControl.Resources> <StackPanel> <StackPanel Orientation="Horizontal" Margin="0,10,0,0"> <TextBlock TextWrapping="Wrap" Margin="5,0,0,0" HorizontalAlignment="Center" VerticalAlignment="Center" Text="Maksymalna liczba z zakresu: "></TextBlock> <TextBox HorizontalAlignment="Center" TextWrapping="Wrap" Margin="10,0,0,0" VerticalAlignment="Center" Name="txbMaxNumber" Text="10"></TextBox> <Button Content="Zapisz opcje" Margin="0,10,0,0" VerticalAlignment="Center" Command="Binding SaveOptions" CommandParameter="Binding Text, Converter=StaticResource StringToIntConverter, ElementName=txbMaxNumber"/> </UserControl> Następnie tworzymy odpowiadający temu widokowi obiekt ViewModel o nazwie OptionsViewModel.cs (dziedziczący oczywiście po ViewModelBase). Dodajemy jedną prostą komendę SaveOptions, która zostanie podpięta do przycisku Zapisz opcje : public class OptionsViewModel : ViewModelBase #region Save Options Command private RelayCommand<int> _savecommand; public RelayCommand<int> SaveOptions if (_savecommand == null) _savecommand = new RelayCommand<int>( x => Messenger.Default.Send<ChangeOptionsMessage>(new ChangeOptionsMessage(x)); ); return _savecommand;

public OptionsViewModel() Jej jedynym przeznaczeniem jest, aby za pomocą obiektu Messenger przesłać dalej otrzymany argument. Wynika on z DataBindingu samego przycisku i jest po prostu zawartością pola tekstowego odpowiadającego za maksymalną liczbę (odpowiednio przekonwertowaną na liczbę całkowitą): <Button Content="Zapisz opcje" Command="Binding SaveOptions" CommandParameter="Binding Text, Converter=StaticResource StringToIntConverter, ElementName=txbMaxNumber"/> Przesyłany komunikat jest typu ChangeOptionsMessage, który to jest naszym własnym typem komunikatu dzięki temu możemy dostosować go tak, aby zawierał tylko takie informacje, jakich potrzebujemy w aktualnym scenariuszu. Dla wygody dziedziczy on po typie MessageBase z MVVM Light Toolkit i zawiera jedną dodatkową właściwość przechowującą maksymalną liczbę do wylosowania. Dodajemy więc do projektu folder Messages, a w nim klasę ChangeOptionsMessages.cs: public class ChangeOptionsMessage : MessageBase public int MaxRange ; set; public ChangeOptionsMessage(int _maxrange) MaxRange = _maxrange; Teraz musimy jeszcze odebrać wysłany komunikat w głównym oknie. Zmieniamy więc plik MainViewModel.cs dodając właściwość MaxRange, rejestrując w konstruktorze akcję reagującą na wysłanie komunikatu typu ChangeOptionsMessage oraz pisząc prosta funkcję obsługującą komunikat HandleChangeOptions() (zmienione elementy zostały zaznaczone na szaro): public class MainViewModel : ViewModelBase private Random rand = new Random(); #region SecretNumberProperty #region Suggestion Property #region IsInProgress Property #region MaxRange Property public const string MaxRangePropertyName = "MaxRange"; private int _maxrange = 10; public int MaxRange return _maxrange;

set if (_maxrange == value) return; //var oldvalue = _maxrange; _maxrange = value; // Update bindings, no broadcast RaisePropertyChanged(MaxRangePropertyName); #region IsSolved #region Start #region CheckGuess Command public MainViewModel()//IDataService dataservice) Messenger.Default.Register<Messages.ChangeOptionsMessage>(this, HandleChangeOptions); if (IsInDesignMode) IsSolved = true; IsInProgress = true; else // Code runs "for real": Connect to service, etc... private void initguess() SecretNumber = rand.next(maxrange) + 1; IsSolved = false; IsInProgress = true; Suggestion = ""; private void HandleChangeOptions(Messages.ChangeOptionsMessage m) this.maxrange = m.maxrange; initguess(); Funkcja initguess() rozpoczyna turę zgadywania z już zmienionym zakresem. Na koniec pozostaje nam jeszcze wprowadzenie drobnych zmian w pliku MainView.xaml, tak, aby możliwe było zobaczenie nowych elementów widoku (zmienione elementy zaznaczono na szaro): <Window x:class="projekt05.mainwindow" xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation" xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml" xmlns:d="http://schemas.microsoft.com/expression/blend/2008" xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006" xmlns:local="clr-namespace:projekt05" xmlns:localview="clr-namespace:projekt05.view" xmlns:i="http://schemas.microsoft.com/expression/2010/interactivity"

xmlns:galasoft_mvvmlight_command="http://www.galasoft.ch/mvvmlight" xmlns:ignore="http://www.ignore.com" mc:ignorable="d ignore" Height="300" Width="300" Title="MVVM Light Application" DataContext="Binding Main, Source=StaticResource Locator"> <Window.Resources> <BooleanToVisibilityConverter x:key="booleantovisibilityconverter"/> <local:stringtointconverter x:key="stringtointconverter"/> </Window.Resources> <DockPanel HorizontalAlignment="Left" LastChildFill="False" Margin="5,0"> <StackPanel DockPanel.Dock="Top"> <StackPanel x:name="spsecret" Orientation="Horizontal" Height="16" Visibility="Binding IsSolved, Converter=StaticResource BooleanToVisibilityConverter, Mode=OneWay"> <TextBlock Height="16" TextWrapping="Wrap" Text="Gratulacje! Sekretna liczba to: " /> <TextBlock x:name="txblsecret" Height="16" TextAlignment="Center" Margin="20,0,0,0" TextWrapping="Wrap" Text="Binding SecretNumber"/> <Button x:name="btnstart" Content="Start" Margin="0,10,0,0" Command="Binding Start, Mode=Default"/> <StackPanel x:name="spguess" Visibility="Binding IsInProgress, Converter=StaticResource BooleanToVisibilityConverter, Mode=OneWay"> <StackPanel Margin="0,10,0,0" Orientation="Horizontal"> <TextBlock Margin="8,0,0,0" TextWrapping="Wrap" Text="Podaj liczbę: " /> <TextBox x:name="txbuserguess" Height="24" TextAlignment="Center" Margin="25,0,0,0" TextWrapping="Wrap" Text="0" Width="50" HorizontalAlignment="Center" VerticalAlignment="Center"> <i:interaction.triggers> <i:eventtrigger EventName="LostFocus"> <GalaSoft_MvvmLight_Command:EventToCommand Command="Binding CheckGuess, Mode=Default" CommandParameter="Binding Text, Converter=StaticResource StringToIntConverter, ElementName=txbUserGuess"/> </i:eventtrigger> </i:interaction.triggers> </TextBox> <Button x:name="btncheck" Content="Sprawdź" Margin="0,10,0,0" Command="Binding CheckGuess" CommandParameter="Binding Text, Converter=StaticResource StringToIntConverter, ElementName=txbUserGuess"/> <TextBlock x:name="txblsuggestion" Margin="0,15,0,0" TextWrapping="Wrap" TextAlignment="Center" Text="Binding Suggestion"/> <localview:optionsview VerticalAlignment="Bottom" DockPanel.Dock="Bottom" Margin="0,0,0,10"/> </DockPanel> </Window>

Po wprowadzeniu powyższych zmian interfejs użytkownika prezentuje się następująco:

Przewodnik przygotowano na podstawie: [1] http://cieplok.blogspot.com/2010/09/podstawy-mvvm-light-toolkit-czesc-1.html [2] http://cieplok.blogspot.com/2010/10/podstawy-mvvm-light-toolkit-czesc-2.html