arrow_back history This page is read only. You can view the source, but not change it. Ask your administrator if you think this is wrong. **''MVVM Pattern - Реалізація патерна''** ---- **Лейбли** 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 виводить введений текст зразу на екран (в деф позицію) Command="{Binding StartStopwatch}" Біндить якусь дію (в нашому випадку це кнопка) </Code> <Code:xaml> <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> </Code> ---- **xaml.cs** __(грубо кажучи це просто main метод!)__ <Code:csharp> namespace CounterSalary { public partial class MainWindow : Window { public MainWindow() { InitializeComponent(); var context = new StopwatchViewModel(); var timer = new TimerMonitore(context); timer.startstopWatch(); DataContext = context; } } } </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>