Добрый день! Учусь и пишу курсовой проект постепенно.
Начал постигать Xamarin.Forms с использованием паттерна MVVM и SQLite. И вот столкнулся с проблемой, на которую нигде ответ не могу найти. На главную страницу в ListView должны выводиться данные, полученные из БД, загруженные в ObservableCollection. И вроде бы данные в коллекцию приходят, и есть Binding с ItemsSource, но на экране либо пустые строки, либо ошибки. В итоге застопорился с этим уже на пару дней.
ViewModel для Model
namespace Pillbox.ViewModels
{
public class MedicineViewModel:BaseViewModel
{
public MedicineViewModel() { }
public MedicineViewModel(Medicine medicine)
{
Id = medicine.Id;
Title = medicine.Title;
Format = medicine.Format;
Method = medicine.Method;
StartMedicationTime = medicine.StartMedicationTime;
FinishMedicationTime = medicine.FinishMedicationTime;
Dosage = medicine.Dosage;
Number = medicine.Number;
Start = medicine.Start;
DurationDays = medicine.DurationDays;
Finish = medicine.Finish;
EveryDay = medicine.EveryDay;
InDays = medicine.InDays;
NonStop = medicine.NonStop;
}
public int Id { get; set; }
private string _title;
public string Title
{
get => _title;
set => Set(ref _title, value);
}
private string _format;
public string Format
{
get => _format;
set => Set(ref _format, value);
}
private string _method;
public string Method
{
get => _method;
set => Set(ref _method, value);
}
private TimeSpan _startMedicationTime;
public TimeSpan StartMedicationTime
{
get => _startMedicationTime;
set => Set(ref _startMedicationTime, value);
}
private TimeSpan _finishMedicationTime;
public TimeSpan FinishMedicationTime
{
get => _finishMedicationTime;
set => Set(ref _finishMedicationTime, value);
}
private float _dosage;
public float Dosage
{
get => _dosage;
set => Set(ref _dosage, value);
}
private int _number;
public int Number
{
get=>_number;
set=>Set(ref _number, value);
}
private DateTime _start;
public DateTime Start { get=>_start; set=>Set(ref _start, value); }
private int _durationDays;
public int DurationDays { get=> _durationDays; set=>Set(ref _durationDays, value); }
private DateTime _finish;
public DateTime Finish { get=> _finish; set=>Set(ref _finish, value); }
private bool _everyDay;
public bool EveryDay { get=> _everyDay; set=>Set(ref _everyDay, value); }
private int _inDays;
public int InDays { get=> _inDays; set=>Set(ref _inDays, value); }
private bool _nonStop;
public bool NonStop { get=> _nonStop; set=>Set(ref _nonStop, value); }
}
}
ViewModel для главной страницы
namespace Pillbox.ViewModels
{
public class MedPageViewModel:BaseViewModel
{
public ICommand AddMedicineCommand { get; protected set; }
public ICommand DeleteMedicineCommand { get; protected set; }
public ICommand SelectMedicineCommand { get; protected set; }
public ICommand LoadMedicinesCommand { get; protected set; }
private bool _isDataLoaded;
private IMedicineDatabase _medicineDB;
private IPageSevices _pageService;
private MedicineViewModel _selectedMedicine;
public MedicineViewModel SelectedMedicine
{
get => _selectedMedicine;
set
{
Set(ref _selectedMedicine, value);
}
}
public ObservableCollection<MedicineViewModel> Medicines { get; set; }
= new ObservableCollection<MedicineViewModel>();
public MedPageViewModel(IPageSevices pageSevices, IMedicineDatabase medicineDatabase)
{
_pageService = pageSevices;
_medicineDB = medicineDatabase;
LoadMedicinesCommand = new Command(async () => await Load());
AddMedicineCommand = new Command(async () => await AddMedicine());
DeleteMedicineCommand = new Command<MedicineViewModel>(async c => await DeleteMedicine(c));
SelectMedicineCommand = new Command<MedicineViewModel>(async c => await SelectMedicine(c));
MessagingCenter.Subscribe<AdditionViewModel, Medicine>
(this, Events.MedicineAdded, OnMedicineAdded);
MessagingCenter.Subscribe<AdditionViewModel, Medicine>
(this, Events.MedicineUpdate, OnMedicineUpdated);
}
private async Task SelectMedicine(MedicineViewModel medicine)
{
if (medicine == null)
return;
SelectedMedicine = null;
await _pageService.PushAsync(new AdditionView(medicine));
}
private async Task Load()
{
Medicines.Clear();
try
{
if (_isDataLoaded)
return;
_isDataLoaded = true;
var medicines = await _medicineDB.UpdateMedicineList();
foreach (var medicine in medicines)
Medicines.Add(new MedicineViewModel(medicine));
}
catch (Exception)
{ throw; }
}
async Task AddMedicine()
{
await _pageService.PushAsync(new AdditionView(new MedicineViewModel()));
}
async Task DeleteMedicine(MedicineViewModel deleteMedicine)
{
if (await _pageService.DisplayAlert("Внимание", $"Вы действительно хотите удалить {deleteMedicine.Title}?", "Да", "Нет"))
{
Medicines.Remove(deleteMedicine);
var medicine = await _medicineDB.GetMedicine(deleteMedicine.Id);
await _medicineDB.DeleteMedicine(medicine);
}
}
}
}
View главной страницы
namespace Pillbox.Views.MainViews
{
[XamlCompilation(XamlCompilationOptions.Compile)]
public partial class MedPage : ContentPage
{
public MedPageViewModel ViewModelMP
{
get => BindingContext as MedPageViewModel;
set => BindingContext = value;
}
public MedPage()
{
var medicineDB = new MedicineDatabase(DependencyService.Get<ISQLiteDb>());
var pageService = new PageService();
ViewModelMP = new MedPageViewModel(pageService, medicineDB);
InitializeComponent();
}
protected override void OnAppearing()
{
ViewModelMP.LoadMedicinesCommand.Execute(null);
base.OnAppearing();
}
void OnMedicineSelected(object sender, SelectedItemChangedEventArgs e)
{
ViewModelMP.SelectMedicineCommand.Execute(e.SelectedItem);
}
}
}
И XAML
<?xml version="1.0" encoding="utf-8" ?>
<ContentPage xmlns="http://xamarin.com/schemas/2014/forms"
xmlns:x="http://schemas.microsoft.com/winfx/2009/xaml"
xmlns:vm="clr-namespace:Pillbox.ViewModels"
x:DataType="vm:MedPageViewModel"
x:Class="Pillbox.Views.MainViews.MedPage"
Title="Мои лекарства" x:Name="medPage">
<Grid>
<Grid.RowDefinitions>
<RowDefinition Height="*"/>
<RowDefinition Height="*"/>
</Grid.RowDefinitions>
<Grid.ColumnDefinitions>
<ColumnDefinition Width="*"/>
<ColumnDefinition Width="*"/>
</Grid.ColumnDefinitions>
<ScrollView Grid.Row="0" Grid.Column="0" Grid.ColumnSpan="2">
<ListView x:Name="listView" ItemsSource="{Binding Medicines}" SelectedItem="{Binding SelectedMedicine, Mode=TwoWay}"
HasUnevenRows="True" SeparatorColor="#005400" ItemSelected="OnMedicineSelected" IsVisible="True" IsTabStop="False" IsEnabled="True" IsRefreshing="False">
<ListView.ItemTemplate>
<DataTemplate>
<ViewCell>
<Grid IsVisible="True" IsEnabled="True">
<Grid.RowDefinitions>
<RowDefinition Height="auto"/>
</Grid.RowDefinitions>
<Label Text="{Binding Source=Medicines, Path=Title}" FontSize="Large"/>
<Label Text="{Binding Source=Medicines, Path=Format}"/>
<Label Text="{Binding Source=Medicines, Path=Method}"/>
</Grid>
</ViewCell>
</DataTemplate>
</ListView.ItemTemplate>
</ListView>
</ScrollView>
<Button Grid.Row="1" Grid.Column="1" Text="+ Добавить" FontSize="Medium" FontAttributes="None" TextColor="White"
BackgroundColor="#13bd13" BorderRadius="75" HorizontalOptions="End" VerticalOptions="End"
Command="{Binding AddMedicineCommand}" Margin="0,0,30,30"/>
</Grid>
</ContentPage>