Answer the question
In order to leave comments, you need to log in
The ListView does not display the data from the ObservableCollection and the XAML refuses to bind. How to fix?
Good afternoon! I study and write a course project gradually.
Began to comprehend Xamarin.Forms using MVVM pattern and SQLite. And I've run into a problem that I can't find the answer to anywhere. The main page in the ListView should display data received from the database, loaded into the ObservableCollection. And it seems that the data comes to the collection, and there is a Binding with ItemsSource, but there are either empty lines or errors on the screen. As a result, I stalled with this for a couple of days.
ViewModel to 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); }
}
}
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);
}
}
}
}
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);
}
}
}
<?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>
Answer the question
In order to leave comments, you need to log in
You are using compiled bindings, which means you need to specify the type explicitly for child elements as well. At least until it's fixed in XF
Adding x:DataType to a ContentPage breaks nested
o
x:DataType="vm:MedicineViewModel"
...
<ListView.ItemTemplate>
<DataTemplate x:DataType="vm:MedicineViewModel">
<ViewCell>
<ViewCell.View>
<StackLayout>
<Label FontSize="Large" Text="{Binding Title}" />
<Label FontSize="Small" Text="{Binding Format}" />
<Label FontSize="Small" Text="{Binding Method}" />
</StackLayout>
</ViewCell.View>
</ViewCell>
</DataTemplate>
</ListView.ItemTemplate>
Didn't find what you were looking for?
Ask your questionAsk a Question
731 491 924 answers to any question