Создание Model и ViewModel
Теперь, когда у нас есть основное представление на экране, давайте подумаем, как мы могли бы отобразить в нем реальные данные из базы данных или чего-то подобного. Самый очевидный и традиционный способ сделать это — загрузить данные в конструктор представления и создать CheckBox
для каждого элемента TODO в коде. Однако такой способ имеет несколько недостатков:
- Мы не можем использовать XAML
- Мы должны написать код, чтобы реагировать на изменения в данных и обновлять отображение.
- Это не подлежит модульному тестированию
Эти соображения могут показаться не важными для небольшого приложения, но по мере роста вашего приложения они становятся все более и более серьезными проблемами: особенно в части тестируемости.
Существует лучший способ! Мы упомянули шаблон MVVM в начале этого руководства, и именно его мы собираемся использовать сейчас.
Создайте модель
Первое, что нужно сделать, это создать модель, которая будет представлять наши данные так, как они будут храниться в базе данных. Наша модель будет довольно простой: каждый элемент TODO будет состоять из текстового описания и логического значения, указывающего, отмечен ли этот элемент.
Поместите следующий класс в каталог Models вашего проекта:
Models/TodoItem.cs
namespace Todo.Models { public class TodoItem { public string Description { get; set; } public bool IsChecked { get; set; } } }
Создайте (поддельную) базу данных
Мы могли бы использовать что-то вроде Entity Framework для чтения этих данных из базы данных SQLite, но поскольку это учебник по Avalonia, а не Entity Framework, мы на самом деле не будем использовать базу данных. Вместо этого мы просто заполним наши модели из массива.
Мы сделаем это в сервисе под названием Database
и поместим его в каталог Services
:
Services/Database.cs
using System.Collections.Generic; using Todo.Models; namespace Todo.Services { public class Database { public IEnumerable<TodoItem> GetItems() => new[] { new TodoItem { Description = "Walk the dog" }, new TodoItem { Description = "Buy some milk" }, new TodoItem { Description = "Learn Avalonia", IsChecked = true }, }; } }
Создайте модель представления
Теперь нам понадобится модель представления, представляющая список. Это класс, который будет предоставлять данные для нашего представления.
Мы уже создали представление и назвали его TodoListView
, поэтому связанная модель представления будет называться TodoListViewModel
. Поместите этот класс в каталог ViewModels
в вашем проекте:
ViewModels/TodoListViewModel.cs
using System.Collections.Generic; using System.Collections.ObjectModel; using Todo.Models; namespace Todo.ViewModels { public class TodoListViewModel : ViewModelBase { public TodoListViewModel(IEnumerable<TodoItem> items) { Items = new ObservableCollection<TodoItem>(items); } public ObservableCollection<TodoItem> Items { get; } } }
Опять же, наша модель представления на данном этапе очень проста. Он просто берет коллекцию моделей TodoItem
в своем конструкторе и помещает их в ObservableCollection
, которая доступна через свойство Items
.
Следует обратить внимание на использование класса ViewModelBase
. Важность этого станет ясна в ближайшее время.
Создайте экземпляр TodoListViewModel
Мы видели, что наша модель TodoListViewModel
требует, чтобы коллекция моделей TodoItem
передавалась ее конструктору, но откуда берутся эти элементы? Где создается TodoListViewModel
?
Что ж, теперь у нас есть два представления и две модели представлений:
MainWindow
(создается по шаблону)MainWindowViewModel
(создается по шаблону)TodoListView
(создано нами)TodoListViewModel
(создано нами)
Если вы вспомните, когда мы создавали представления, вы помните, что наши представления имеют отношение родитель-потомок (TodoListView
является дочерним элементом MainWindow
). Это может дать нам подсказку: MainWindowViewModel
должен создать TodoListViewModel
!
Отредактируйте файл MainWindowViewModel.cs
следующим образом:
MainWindowViewModel.cs
using Todo.Services; namespace Todo.ViewModels { class MainWindowViewModel : ViewModelBase { public MainWindowViewModel(Database db) { List = new TodoListViewModel(db.GetItems()); } public TodoListViewModel List { get; } } }
Наконец, отредактируйте метод OnFrameworkInitializationCompleted
в App.axaml.cs
, чтобы создать экземпляр базы данных и передать его в MainWindowViewModel
:
public override void OnFrameworkInitializationCompleted() { base.OnFrameworkInitializationCompleted(); if (ApplicationLifetime is IClassicDesktopStyleApplicationLifetime desktop) { var db = new Database(); desktop.MainWindow = new MainWindow { DataContext = new MainWindowViewModel(db), }; } }
Далее мы собираемся подключить представления для чтения из наших моделей представлений…