I have a small project that has two pages showing a list view. But one of my pages is not working in spite of beeing the same code with just small changes (names of props). The binding context it´s taking the information i need (the Patients list) but the page returns empty. In my other page with the same code the Viewlist works properly. Maybe i'm missing something or could be a typo error i really don't know what's happening. Please help me and if u have suggestions to improve my code please tell me i'm a begginer in xamarin forms.
XAML:
<ListView x:Name="appointmentListView"
SeparatorVisibility="None"
HasUnevenRows="true"
ItemsSource="{Binding Appointments}">
<ListView.Header>
<Grid BackgroundColor="#03A9F4">
<Grid.ColumnDefinitions>
<ColumnDefinition Width="10"/>
<ColumnDefinition Width="*"/>
<ColumnDefinition Width="10"/>
</Grid.ColumnDefinitions>
<Grid.RowDefinitions>
<RowDefinition Height="30"/>
<RowDefinition Height="80"/>
<RowDefinition Height="Auto"/>
<RowDefinition Height="10"/>
</Grid.RowDefinitions>
</Grid>
</ListView.Header>
<ListView.ItemTemplate>
<DataTemplate>
<ViewCell>
<StackLayout Padding="15,10" HorizontalOptions="FillAndExpand" x:DataType="model:Appointment">
<Label VerticalOptions="FillAndExpand" VerticalTextAlignment="Center"
Text="{Binding Patient}"
FontSize="24"/>
</StackLayout>
</ViewCell>
</DataTemplate>
</ListView.ItemTemplate>
</ListView>
Code behind:
[XamlCompilation(XamlCompilationOptions.Compile)]
public partial class AppointmentListViewDetail : ContentPage
{
public AppointmentListViewDetail()
{
InitializeComponent();
BindingContext = new AppointmentListViewModel();
appointmentListView.ItemSelected = (s, e) =>
{
if (e.SelectedItem as Appointment != null)
{
Action goToPage = async () =>
{
await PopupNavigation.Instance.PushAsync(new AppointmentDetailsPopup(e.SelectedItem as Appointment));
appointmentListView.SelectedItem = null;
};
goToPage.Invoke();
}
};
}
protected override void OnAppearing()
{
base.OnAppearing();
MessagingCenter.Subscribe<AppointmentListViewModel>(this, "Reload", (p) =>
{
BindingContext = p;
});
MessagingCenter.Subscribe<AppointmentFilterViewModel>(this, "Filter", (p) =>
{
string? nameFilter = p.NameFilter.Text;
DateTime? startDateFilter = DateTime.ParseExact(p.StartDateFilter.Text, "dd/MM/yyyy", CultureInfo.InvariantCulture);
DateTime? finalDateFilter = DateTime.ParseExact(p.FinalDateFilter.Text, "dd/MM/yyyy", CultureInfo.InvariantCulture);
Status? statusFilter = (Status)Enum.Parse(typeof(Status), p.StatusFilter.Text);
BindingContext = new AppointmentListViewModel(nameFilter, startDateFilter, finalDateFilter, statusFilter);
});
}
ViewModel:
public class AppointmentListViewModel
{
ObservableCollection<Appointment> _appointments;
public ObservableCollection<Appointment> Appointments
{
get { return _appointments; }
set
{
_appointments = value;
OnPropertyChanged(nameof(Appointments));
}
}
public ICommand Filter { get; set; }
public AppointmentListViewModel()
{
var getAppointmentsList = new Action(async () =>
{
Appointments = new ObservableCollection<Appointment>(await Startup.ServiceProvider.GetService<AppointmentService>().ToListAsync());
});
getAppointmentsList.Invoke();
}
public AppointmentListViewModel(string? patient, DateTime? startDate, DateTime? finalDate, Status? status)
{
var getPatientList = new Action(async () =>
{
Appointments = new ObservableCollection<Appointment>(await Startup.ServiceProvider.GetService<AppointmentService>().FilterSearchAsync(patient, startDate, finalDate, status));
});
getPatientList.Invoke();
}
public event PropertyChangedEventHandler PropertyChanged;
public void OnPropertyChanged(string propertyName)
{
PropertyChanged?.Invoke(this, new PropertyChangedEventArgs(propertyName));
}
}
Model:
public class Appointment
{
[PrimaryKey, AutoIncrement]
public int Id { get; set; }
public float Price { get; set; }
public DateTime Date { get; set; }
public Status PaymentStatus { get; set; }
public string Patient { get; set; }
}
CodePudding user response:
I solved this problem using Task.Run().Wait(). I recommend using that if u are trying to get data from the database on your viewmodel.
ViewModel:
public AppointmentListViewModel()
{
Task.Run(async () =>
{
Appointments = new ObservableCollection<Appointment>(await Startup.ServiceProvider.GetService<AppointmentService>().ToListAsync());
}).Wait();
}
Service that contains all operations related to the database:
public AppointmentService()
{
string dbPath = Path.Combine(Environment.GetFolderPath(Environment.SpecialFolder.LocalApplicationData), "patient.db3");
_database = new SQLiteAsyncConnection(dbPath);
_database.CreateTableAsync<Appointment>().Wait();
}
public Task<List<Appointment>> ToListAsync()
{
return _database.Table<Appointment>().ToListAsync();
}