IMI docs

Trace: mvvm

Mvvm

This is an old revision of the document!


MVVM Pattern - Реалізація патерна


Лейбли and Binding в XAML (в XAML забіндити можна все що завгодно!)

Foreground="Red"                         Міняє колір вмісту
FontSize="50"                            Величена вмісту
FontFamily="Segoe UI"                    Які шрифти будуть використані
Content="{Binding Time}"                 Бінд який падає в клас StopwatchViewModel  з інтерфейсом  INotifyPropertyChanged
HorizontalContentAlignment="Center"      Вірівнення по ширині
VerticalContentAlignment="Center"        Вірівнення по висоті
<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 (тому що в конструкторі НЕ ПРИПУСТИМО робити запуск програми)

—-

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)));
            }
        }
    }
}

Даємо івенти на nameof - будь це хоч Margin хоч Context (Це один з методів реалізування Біндінгів)

Якщо ви імплементуєте інтерфейс 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();
        }
    }
}

Рівень сервісу (потрібен для реалізації логіки) Цей клас реалізовує логіку таймера, а саме В конструкторі створюється івент на таймер

Ця залупа робить логіку йобаного таймера В конструкторі заборонено робити любу логіку Позволено давати ІВЕНТИ та передавати параметр який заходить в конструктор, в MainWindow _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);