Trace:
Differences
This shows you the differences between two versions of the page.
| Both sides previous revision Previous revision Next revision | Previous revision | ||
|
mvvm [2019/01/11 09:11] superuser |
mvvm [2019/01/13 12:01] (current) yura |
||
|---|---|---|---|
| Line 1: | Line 1: | ||
| - | **''MVVM Pattern - Реалізація патерна''** | + | **''MVVM Pattern - Реалізація патерна''** |
| ---- | ---- | ||
| **Лейбли** and **Binding** в XAML __(в XAML забіндити можна все що завгодно!)__ | **Лейбли** and **Binding** в XAML __(в XAML забіндити можна все що завгодно!)__ | ||
| + | <Code:csharp> | ||
| + | Foreground="Red" Міняє колір вмісту | ||
| + | FontSize="50" Величена вмісту | ||
| + | FontFamily="Segoe UI" Які шрифти будуть використані | ||
| + | HorizontalContentAlignment="Center" Вірівнення по ширині | ||
| + | VerticalContentAlignment="Center" Вірівнення по висоті | ||
| + | Margin="0, 0, 0, -200" Зсунути в низ на 200 px | ||
| + | Content="{Binding Time}" Бінд який падає в клас StopwatchViewModel : INotifyPropertyChanged | ||
| + | Content="{Binding Time, TargetNullValue='00.00 UAH'}" TargetNullValue виводить введений текст зразу на екран (в деф позицію) | ||
| - | <Code:csharp> | + | Command="{Binding StartStopwatch}" Біндить якусь дію (в нашому випадку це кнопка) |
| - | Foreground="Red" Міняє колір вмісту | + | </Code> |
| - | FontSize="50" Величена вмісту | + | |
| - | FontFamily="Segoe UI" Які шрифти будуть використані | + | |
| - | Content="{Binding Time}" Бінд який падає в клас StopwatchViewModel з інтерфейсом INotifyPropertyChanged | + | |
| - | HorizontalContentAlignment="Center" Вірівнення по ширині | + | |
| - | VerticalContentAlignment="Center" Вірівнення по висоті | + | |
| - | </Code> | + | |
| <Code:xaml> | <Code:xaml> | ||
| <Label Content="{Binding Time}" Foreground="Red" FontFamily="Segoe UI" FontSize="50" VerticalContentAlignment="Center" ></Label> | <Label Content="{Binding Time}" Foreground="Red" FontFamily="Segoe UI" FontSize="50" VerticalContentAlignment="Center" ></Label> | ||
| <Label Margin="{Binding Xyi}" FontFamily="Segoe UI" FontSize="50" HorizontalContentAlignment="Center"></Label> | <Label Margin="{Binding Xyi}" FontFamily="Segoe UI" FontSize="50" HorizontalContentAlignment="Center"></Label> | ||
| </Code> | </Code> | ||
| + | |||
| + | |||
| ---- | ---- | ||
| **xaml.cs** __(грубо кажучи це просто main метод!)__ | **xaml.cs** __(грубо кажучи це просто main метод!)__ | ||
| - | * Unordered List ItemМетод по дефу, потрібен для виклику (НЕ РЕАЛІЗАЦІЇ) реалізовуючих класів | + | |
| - | * Unordered List ItemDataContext потрібен для того щоб достукатись до МОДЕЛЕЙ класу StopwatchViewModel з інтерфейсом INotifyPropertyChanged (Дефолтна штука, якось працює під капотом) | + | |
| - | * Unordered List Itemtimer реалізовує TimerMonitore який приймає конструктор класу StopwatchViewModel | + | |
| - | * Unordered List Itemпри виклику timer.startstopWatch(); запускає DispatcherTimer і Stopwatch (тому що в конструкторі НЕ ПРИПУСТИМО робити запуск програми) | + | |
| <Code:csharp> | <Code:csharp> | ||
| namespace CounterSalary | namespace CounterSalary | ||
| Line 37: | Line 39: | ||
| } | } | ||
| </Code> | </Code> | ||
| + | |||
| + | * Любі класи в XAML використовується тільки для виклику **(НЕ РЕАЛІЗАЦІЇ ЛОГІКИ)** | ||
| + | * DataContext потрібен для того щоб достукатись до МОДЕЛЕЙ класу StopwatchViewModel з інтерфейсом INotifyPropertyChanged (Дефолтна штука, якось працює під капотом) | ||
| + | * timer реалізовує TimerMonitor який приймає конструктор класу StopwatchViewModel | ||
| + | * При виклику timer.startstopWatch(); запускає DispatcherTimer і Stopwatch (тому що в конструкторі НЕ ПРИПУСТИМО робити запуск програми) | ||
| + | |||
| + | ---- | ||
| + | **Бінд кнопки виглядає наступним чином** | ||
| + | <Code:csharp> | ||
| + | <Button Content="Click" Command="{Binding StartStopwatch}" Width="100" Height="25" HorizontalContentAlignment="Center" Margin="0, 0, 0, -200"></Button> | ||
| + | </Code> | ||
| + | |||
| + | |||
| + | **Реалізація класу ButtonCommand через інтерфейс ICommand** | ||
| + | <Code:csharp> | ||
| + | namespace CounterSalary.ViewModel | ||
| + | { | ||
| + | public class ButtonCommand : ICommand | ||
| + | { | ||
| + | private readonly Action action; | ||
| + | public event EventHandler CanExecuteChanged; | ||
| + | |||
| + | public ButtonCommand(Action action) | ||
| + | { | ||
| + | this.action = action; | ||
| + | } | ||
| + | |||
| + | public bool CanExecute(object parameter) | ||
| + | { | ||
| + | return true; | ||
| + | } | ||
| + | |||
| + | public void Execute(object parameter) | ||
| + | { | ||
| + | action(); | ||
| + | } | ||
| + | } | ||
| + | } | ||
| + | |||
| + | </Code> | ||
| + | **Робиться для того щоб потім можна було його реалізувати через моделі** 👇👇👇 | ||
| + | <Code:csharp> | ||
| + | public ButtonCommand StartStopwatch { get; set; } = new ButtonCommand(() => | ||
| + | { | ||
| + | _timer.startStopwatch(); | ||
| + | }); | ||
| + | </Code> | ||
| + | ---- | ||
| + | **Даємо івенти на nameof** - будь це хоч Margin хоч Context __(Це один з методів реалізування Біндінгів)__ | ||
| + | <Code:csharp> | ||
| + | delegate { } - пустая функция, але може бути і не пустою, завдяки неї з варки мажна зробити метод | ||
| + | </Code> | ||
| + | <Code:csharp> | ||
| + | namespace CounterSalary.ViewModel | ||
| + | { | ||
| + | public class StopwatchViewModel : INotifyPropertyChanged | ||
| + | { | ||
| + | public event PropertyChangedEventHandler PropertyChanged=delegate { }; | ||
| + | string _count; | ||
| + | string _count1; | ||
| + | |||
| + | public string Time { | ||
| + | get { return _count; } | ||
| + | set { _count = value; | ||
| + | PropertyChanged(this, new PropertyChangedEventArgs(nameof(Time))); | ||
| + | } | ||
| + | } | ||
| + | |||
| + | public string Xyi { | ||
| + | get { return _count1; } | ||
| + | set { _count1 = value; | ||
| + | PropertyChanged(this, new PropertyChangedEventArgs(nameof(Xyi))); | ||
| + | } | ||
| + | } | ||
| + | } | ||
| + | } | ||
| + | </Code> | ||
| + | |||
| + | Якщо ви імплементуєте інтерфейс **INotifyPropertyChanged**, то ви маєте реалізувати **event PropertyChanged**, і відправити його кожен раз, коли значення міняється. | ||
| + | |||
| + | ---- | ||
| + | **Рівень сервісу** __(потрібен для реалізації логіки)__ | ||
| + | <Code:csharp> | ||
| + | namespace CounterSalary.Service | ||
| + | { | ||
| + | public class TimerMonitore | ||
| + | { | ||
| + | private Stopwatch stopWatch = new Stopwatch(); | ||
| + | private DispatcherTimer dt = new DispatcherTimer(); | ||
| + | private TimeSpan ts; | ||
| + | private StopwatchViewModel _model; | ||
| + | | ||
| + | public TimerMonitore(StopwatchViewModel model) | ||
| + | { | ||
| + | dt.Tick += new EventHandler(dtTicker); | ||
| + | _model = model; | ||
| + | } | ||
| + | |||
| + | private void dtTicker(object sender, EventArgs e) | ||
| + | { | ||
| + | ts = stopWatch.Elapsed; | ||
| + | string currentTime = String.Format("{0:00}.{1:00}", ts.TotalSeconds, ts.Milliseconds / 10); | ||
| + | _model.Time = currentTime; | ||
| + | _model.Xyi="400"; | ||
| + | } | ||
| + | |||
| + | public void startstopWatch() | ||
| + | { | ||
| + | dt.Start(); | ||
| + | stopWatch.Start(); | ||
| + | } | ||
| + | } | ||
| + | } | ||
| + | </Code> | ||
| + | |||
| + | |||
| + | Цей клас **реалізовує логіку** таймера, а саме | ||
| + | В конструкторі створюється івент на таймер | ||
| + | _model.Time = currentTime Заходить в INotifyPropertyChanged і сетить нове значення рівне currentTime - і таким чином в лейблі міняється значення | ||
| + | |||
| + | |||
| + | **Пояснення коду нище!**👇 | ||
| + | |||
| + | <Code:csharp> | ||
| + | DispatcherTimer dt = new DispatcherTimer(); //Створення нового екземпляра DispatcherTimer | ||
| + | dt.Interval = TimeSpan.FromSeconds(1); //Буде використовувати івент який нище прив*язаний 1 раз в секунду | ||
| + | |||
| + | dt.Tick += dtTicker; //Підписатись на івент | ||
| + | dt.Tick -= dtTicker; //Відписатись від івенту | ||
| + | dt.Tick += new EventHandler(dtTicker); //Ідентичний пропис | ||
| + | |||
| + | dt.Start(); //Стартує івент в багатопоточносі | ||
| + | stopWatch.Start(); //Стартує раніше обявлений Stopwatch (Секундомір) | ||
| + | |||
| + | private Stopwatch stopWatch = new Stopwatch(); //Створює новий екземпляр секундоміра | ||
| + | TimeSpan ts = stopWatch.Elapsed; //Cтворює секундомір | ||
| + | |||
| + | //0:ХХ Підписатись на перший івент - ts.TotalSeconds | ||
| + | //1:ХХ Підписатись на перший івент - ts.Milliseconds | ||
| + | //ts.TotalSeconds Абсолютний час - іде дальше чим 60 секунд | ||
| + | //ts.Seconds - на 60 секунді скидується до 0 | ||
| + | string currentTime = String.Format("{0:00}.{1:00}", ts.TotalSeconds, ts.Milliseconds / 10); | ||
| + | </Code> | ||
| + | |||
