Trace: • mvvm
Mvvm
This is an old revision of the document!
MVVM Pattern - Реалізація патерна
—-
Лейбли and Binding в XAML (в XAML забіндити можна все що завгодно!)
Foreground="Red" Міняє колір вмісту
FontSize="50" Величена вмісту
FontFamily="Segoe UI" Які шрифти будуть використані
HorizontalContentAlignment="Center" Вірівнення по ширині
VerticalContentAlignment="Center" Вірівнення по висоті
Content="{Binding Time}" Бінд який падає в клас StopwatchViewModel з інтерфейсом INotifyPropertyChanged
Content="{Binding Time, TargetNullValue='00.00 UAH'}" TargetNullValue виводить введений текст зразу на екра
Command="{Binding StartStopwatch}" Біндить якусь дію (в нашому випадку це кнопка)
<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>
xaml.cs (грубо кажучи це просто main метод!)
namespace CounterSalary
{
public partial class MainWindow : Window
{
public MainWindow()
{
InitializeComponent();
var context = new StopwatchViewModel();
var timer = new TimerMonitore(context);
timer.startstopWatch();
DataContext = context;
}
}
}
- Любі класи в XAML використовується тільки для виклику (НЕ РЕАЛІЗАЦІЇ ЛОГІКИ)
- DataContext потрібен для того щоб достукатись до МОДЕЛЕЙ класу StopwatchViewModel з інтерфейсом INotifyPropertyChanged (Дефолтна штука, якось працює під капотом)
- timer реалізовує TimerMonitor який приймає конструктор класу StopwatchViewModel
- При виклику timer.startstopWatch(); запускає DispatcherTimer і Stopwatch (тому що в конструкторі НЕ ПРИПУСТИМО робити запуск програми)
Реалізація класу ButtonCommand через інтерфейс ICommand
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();
}
}
}
Робиться для того щоб потім можна було його реалізувати через моделі
Даємо івенти на nameof - будь це хоч Margin хоч Context (Це один з методів реалізування Біндінгів)
delegate { } - пустая функция, але може бути і не пустою, завдяки неї з варки мажна зробити метод
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)));
}
}
}
}
Якщо ви імплементуєте інтерфейс INotifyPropertyChanged, то ви маєте реалізувати event PropertyChanged, і відправити його кожен раз, коли значення міняється.
Рівень сервісу (потрібен для реалізації логіки)
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();
}
}
}
Цей клас реалізовує логіку таймера, а саме В конструкторі створюється івент на таймер _model.Time = currentTime Заходить в INotifyPropertyChanged і сетить нове значення рівне currentTime - і таким чином в лейблі міняється значення
Пояснення коду нище!👇
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);
