Unable to build my app after connecting it to sqlite - sqlite

Ok so when i run my app i just get a : System.AggregateException which i tried to spot with the debuguer
and it brings me to this function in the AgendaDatabase.cs file :
public AgendaDatabase(string dbPath)
{
database = new SQLiteAsyncConnection(dbPath);
database.CreateTableAsync<Agenda>().Wait();
}
Before targetting the System.AggregateException with the debugger i also had a SystemAggregateException for this function in AcceuilPage.xaml.cs:
protected override async void OnAppearing()
{
base.OnAppearing();
AgendaCollection.ItemsSource = await App.Database.GetAgendasAsync();
}
and when i execute one more it says : unhandled exception : SQLite.SQLiteException: no such table: Agenda which is weird cause the code is supposed to create it if it doesn't exist.
This is the tutorial i am following : https://learn.microsoft.com/en-us/xamarin/get-started/quickstarts/database?pivots=windows
Thanks for your help.
I've done the steps mutiple time, even listened to similar tutorial with no solution on how to fix it : heres the code :
AgendaDatabase.cs (in Database folder)
using System;
using System.Collections.Generic;
using System.Text;
using SQLite;
using Calculette.Models;
using System.Threading.Tasks;
namespace Calculette.Database
{
public class AgendaDatabase
{
readonly SQLiteAsyncConnection database;
public AgendaDatabase(string dbPath)
{
database = new SQLiteAsyncConnection(dbPath);
database.CreateTableAsync<Agenda>().Wait();
}
public Task<List<Agenda>> GetAgendasAsync()
{
return database.Table<Agenda>().ToListAsync();
}
public Task<Agenda> GetAgendaAsync(int id)
{
return database.Table<Agenda>()
.Where(i => i.ID == id)
.FirstOrDefaultAsync();
}
public Task<int> SaveAgendaAsync(Agenda agenda)
{
if (agenda.ID != 0)
{
return database.UpdateAsync(agenda);
}
else
{
return database.InsertAsync(agenda);
}
}
public Task<int> DeleteAgendaAsync(Agenda agenda)
{
return database.DeleteAsync(agenda);
}
}
}
Agenda.cs in the Models folder
using System;
using System.Collections.Generic;
using System.Collections.ObjectModel;
using System.Text;
using SQLite;
using Calculette.Database;
namespace Calculette.Models
{
public class Agenda
{
[PrimaryKey, AutoIncrement]
public int ID { get; set; }
public string Topic { get; set; }
public string Duration { get; set; }
public DateTime Date { get; set; }
public ObservableCollection<Speaker> Speakers { get; set; }
public string Color { get; set; }
public string Name { get; set; }
public string Time { get; set; }
}
}
AcceuilPage.xaml in the Views folder
<TabbedPage xmlns="http://xamarin.com/schemas/2014/forms"
xmlns:x="http://schemas.microsoft.com/winfx/2009/xaml"
xmlns:local="clr-namespace:Calculette"
xmlns:pv="clr-namespace:Xamarin.Forms.PancakeView;assembly=Xamarin.Forms.PancakeView"
x:Class="Calculette.MainPage"
BarBackgroundColor = "White"
BarTextColor="#008A00">
<ContentPage Icon="icontache.png" BackgroundColor="#F6F8F9">
<ContentPage.Content>
<!-- ScrollView nous permet d'avoir une page scrollable-->
<ScrollView Orientation="Vertical">
<CollectionView Grid.Row="2" Margin="25" HorizontalOptions="FillAndExpand" VerticalOptions="FillAndExpand"
SelectionMode="None" x:Name="AgendaCollection">
<CollectionView.Header>
<StackLayout Orientation="Horizontal" Spacing="220">
<Label Text="Agenda" TextColor="Black" FontSize="18"/>
<ImageButton Source="iconplus.png" HeightRequest="30" WidthRequest="30" Clicked="GoToNewFormPage"></ImageButton>
</StackLayout>
</CollectionView.Header>
<CollectionView.ItemsLayout>
<LinearItemsLayout Orientation="Vertical" ItemSpacing="20"/>
</CollectionView.ItemsLayout>
<CollectionView.ItemTemplate >
<DataTemplate>
<pv:PancakeView HasShadow="True" BackgroundColor="White" VerticalOptions="StartAndExpand "
HorizontalOptions="FillAndExpand" >
<Grid VerticalOptions="StartAndExpand" HorizontalOptions="FillAndExpand">
<Grid.ColumnDefinitions>
<ColumnDefinition Width="Auto"/>
<ColumnDefinition Width="*"/>
</Grid.ColumnDefinitions>
<BoxView BackgroundColor="{Binding Color}" WidthRequest="3" HorizontalOptions="Start"
VerticalOptions="FillAndExpand"/>
<Expander Grid.Column="1">
<Expander.Header>
<Grid HorizontalOptions="FillAndExpand">
<Grid.ColumnDefinitions>
<ColumnDefinition Width="*"/>
<ColumnDefinition Width="Auto"/>
<ColumnDefinition Width="3.5*"/>
</Grid.ColumnDefinitions>
<StackLayout HorizontalOptions="Center" VerticalOptions="Center">
<Label Text="{Binding Date, StringFormat='{0:dd}'}" TextColor="#008A00" FontSize="27"
HorizontalOptions="Center"/>
<Label Text="{Binding Date, StringFormat='{0:MMMM}'}" TextColor="Black" FontSize="10"
HorizontalOptions="Center" Margin="0,-10,0,0" FontAttributes="Bold"/>
<ImageButton Source="iconplus.png" HorizontalOptions="Center" HeightRequest="30" WidthRequest="30" Clicked="GoToFormPage"></ImageButton>
</StackLayout>
<BoxView Grid.Column="1" BackgroundColor="#F2F4F8" WidthRequest="1" HorizontalOptions="Start"
VerticalOptions="FillAndExpand"/>
<StackLayout Grid.Column="2" HorizontalOptions="Start" VerticalOptions="Center" Margin="20">
<Label Text="{Binding Topic}" TextColor="#008A00" FontSize="15" FontAttributes="Bold"/>
<Label Text="{Binding Duration}" TextColor="#2F3246" FontSize="12" Margin="0,-10,0,0"/>
</StackLayout>
</Grid>
</Expander.Header>
<Grid HorizontalOptions="FillAndExpand">
<Grid.ColumnDefinitions>
<ColumnDefinition Width="*"/>
<ColumnDefinition Width="Auto"/>
<ColumnDefinition Width="3.5*"/>
</Grid.ColumnDefinitions>
<BoxView Grid.Column="1" BackgroundColor="#F2F4F8" WidthRequest="1" HorizontalOptions="Start"
VerticalOptions="FillAndExpand"/>
<StackLayout Grid.Column="2" Spacing="10">
<Label Text="Tâches" TextColor="Black" FontSize="15" Margin="20,0"/>
<StackLayout BindableLayout.ItemsSource="{Binding Speakers}" HorizontalOptions="Start" VerticalOptions="Center" Margin="20,0,0,20">
<BindableLayout.ItemTemplate>
<DataTemplate>
<Label TextColor="#2F3246" FontSize="12">
<Label.FormattedText>
<FormattedString>
<FormattedString.Spans>
<Span Text="{Binding Time}"/>
<Span Text=" - "/>
<Span Text="{Binding Name}" FontAttributes="Bold"/>
</FormattedString.Spans>
</FormattedString>
</Label.FormattedText>
</Label>
</DataTemplate>
</BindableLayout.ItemTemplate>
</StackLayout>
</StackLayout>
</Grid>
</Expander>
</Grid>
</pv:PancakeView>
</DataTemplate>
</CollectionView.ItemTemplate>
</CollectionView>
</ScrollView>
</ContentPage.Content>
</ContentPage>
AcceuilPage.xaml.cs
using Calculette.ViewModel;
using Calculette.Models;
using System;
using System.Collections.Generic;
using System.Collections.ObjectModel;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using Xamarin.Forms;
using Xamarin.Forms.PancakeView;
namespace Calculette
{
public partial class MainPage : TabbedPage
{
public MainPage()
{
InitializeComponent();
this.BindingContext = this;
}
protected async void GoToFormPage(object sender, EventArgs e)
{
await Navigation.PushAsync(new Views.AgendaItemDetailPage());
}
protected async void GoToNewFormPage(object sender, EventArgs e)
{
await Navigation.PushAsync(new Views.NewFormPage());
}
protected override async void OnAppearing()
{
base.OnAppearing();
AgendaCollection.ItemsSource = await App.Database.GetAgendasAsync();
}
}
}

First of all, you must specify database model, because sqlite is not able to create table from your model.
namespace Calculette.Models
{
[Table("Agenda")]
public class Agenda
{
[PrimaryKey, AutoIncrement, Column("ID")]
public int ID { get; set; }
[Column("Topic")]
public string Topic { get; set; }
[Column("Duration")]
public string Duration { get; set; }
//public DateTime Date { get; set; }
//public ObservableCollection<Speaker> Speakers { get; set; }
[Column("Color")]
public string Color { get; set; }
[Column("Name")]
public string Name { get; set; }
[Column("Time")]
public string Time { get; set; }
}
}
Be aware that sqlite does not support
public DateTime Date { get; set; }
public ObservableCollection<Speaker> Speakers { get; set; }

Related

Can't get the CollectionView to Display data in my collection

I am trying to make a collectionView display the items in a collection I have created but that doe snot work at all. I have been looking around to understand the issue but I can't figure it out. Can someone help me out ? See below the XAML code for a custom control I created and following it the code behind in c#
'''
<StackLayout xmlns="http://schemas.microsoft.com/dotnet/2021/maui"
xmlns:x="http://schemas.microsoft.com/winfx/2009/xaml"
x:Class="CustomControls.CustomControl.DataGrid2"
xmlns:local="clr-namespace:CustomControls.CustomControl"
HeightRequest="500"
WidthRequest="500"
Orientation="Horizontal">
<CollectionView x:Name="c2" ItemsLayout="VerticalList" x:DataType="local:DataGrid2" ItemsSource="{Binding Data2see}" >
<CollectionView.Header>
<StackLayout BackgroundColor="LightGray">
<Label Margin="10,0,0,0"
Text="Monkeys"
FontSize="Small"
FontAttributes="Bold" />
</StackLayout>
</CollectionView.Header>
<CollectionView.Footer>
<StackLayout BackgroundColor="LightGray">
<Label Margin="10,0,0,0"
Text="Friends of Xamarin Monkey"
FontSize="Small"
FontAttributes="Bold" />
</StackLayout>
</CollectionView.Footer>
<CollectionView.ItemTemplate>
<DataTemplate x:DataType="local:SomeDataExemple2">
<Grid Padding="10" ColumnDefinitions="100,100,100">
<Button Grid.Column="0" Text ="clickmenow2"/>
<Entry Grid.Column= "1" Text="{Binding Name}"/>
<Entry Grid.Column="2" Text="{Binding First_name}"/>
</Grid>
</DataTemplate>
</CollectionView.ItemTemplate>
</CollectionView>
</StackLayout>
namespace CustomControls.CustomControl
{ using System.Collections.Specialized;
using System.Collections.Generic;
using System.Collections;
using System.Collections.ObjectModel;
public partial class DataGrid2 : StackLayout
{
public DataGrid2()
{
Data2see = new Collection<SomeDataExemple2>();
Data2see.Add(new SomeDataExemple2("hamid", "britel"));
Data2see.Add(new SomeDataExemple2("mernissi", "wadie"));
Data2see.Add(new SomeDataExemple2("mhamed", "chraibi"));
Data2see.Add(new SomeDataExemple2("yazid", "alaoui"));
Data2see.Add(new SomeDataExemple2("amine", "gogole"));
Data2see.Add(new SomeDataExemple2("mehdi", "harras"));
InitializeComponent();
//c2.ItemsSource = Data;
}
public Collection<SomeDataExemple2> Data2see
{
get;
set;
}
}
public class SomeDataExemple2
{
public SomeDataExemple2(string name1, string name2)
{
Name = name1;
First_name = name2;
}
public string Name
{
get; set;
}
public string First_name
{
get;
set;
}
}}
.xaml code, you can use ContentPage instead of StackLayout
<ContentPage xmlns="http://schemas.microsoft.com/dotnet/2021/maui"
xmlns:x="http://schemas.microsoft.com/winfx/2009/xaml"
x:Class="MauiApp_test.MainPage"
xmlns:local="clr-namespace:MauiApp_test"
HeightRequest="500"
WidthRequest="500">
<CollectionView x:Name="c2" ItemsLayout="VerticalList" >
<CollectionView.Header>
<StackLayout BackgroundColor="LightGray">
<Label Margin="10,0,0,0"
Text="Monkeys"
FontSize="Small"
FontAttributes="Bold" />
</StackLayout>
</CollectionView.Header>
<CollectionView.Footer>
<StackLayout BackgroundColor="LightGray">
<Label Margin="10,0,0,0"
Text="Friends of Xamarin Monkey"
FontSize="Small"
FontAttributes="Bold" />
</StackLayout>
</CollectionView.Footer>
<CollectionView.ItemTemplate>
<DataTemplate>
<Grid Padding="10" ColumnDefinitions="100,100,100">
<Button Grid.Column="0" Text ="clickmenow2"/>
<Entry Grid.Column= "1" Text="{Binding Name}"/>
<Entry Grid.Column="2" Text="{Binding First_name}"/>
</Grid>
</DataTemplate>
</CollectionView.ItemTemplate>
</CollectionView>
.xaml.cs
using System.Collections.ObjectModel;
namespace MauiApp_test;
public partial class MainPage : ContentPage
{
public Collection<SomeDataExemple2> Data2see
{
get;
set;
}
public MainPage()
{
InitializeComponent();
}
protected override void OnAppearing()
{
base.OnAppearing();
Data2see = new Collection<SomeDataExemple2>();
Data2see.Add(new SomeDataExemple2("hamid", "britel"));
Data2see.Add(new SomeDataExemple2("mernissi", "wadie"));
Data2see.Add(new SomeDataExemple2("mhamed", "chraibi"));
Data2see.Add(new SomeDataExemple2("yazid", "alaoui"));
Data2see.Add(new SomeDataExemple2("amine", "gogole"));
Data2see.Add(new SomeDataExemple2("mehdi", "harras"));
c2.ItemsSource = Data2see
.ToList();
}
public class SomeDataExemple2
{
public SomeDataExemple2(string name1, string name2)
{
Name = name1;
First_name = name2;
}
public string Name
{
get; set;
}
public string First_name
{
get;
set;
}
}
}

Change toObservableCollection does not update UI

I am new to Xamarin Forms. So therefore I have a trouble with the UI updating. I had create a collection view to display a list of data. Besides that I also created a button for the user to update remarks. While the user click the button, it will call OnRemarksButtonClickedAsync(APIPatrolD obj) and update the patrold_remark to the ObservationList. I already debug and ensure that the remarks had been store in the DAPIPatrolDSiapImbasList but it unable to update to the UI. Did anyone known why?
Below is my source code.
APIDATA Class
public class APIPatrolH
{
public string patrolh_ID { get; set; }
public DateTime patrolh_planDateTime { get; set; }
public DateTime patrolh_actualDateTime { get; set; }
public string patrolh_actualBy { get; set; }
public string patrolh_route { get; set; }
public string patrolh_routeDesc { get; set; }
public APIPatrolD[] patrolh_patrold { get; set; }
}
public class APIPatrolD
{
public string patrold_ID { get; set; }
public string patrold_loc { get; set; }
public int patrold_seq { get; set; }
public string patrold_desc { get; set; }
public byte[] patrold_image { get; set; }
public string patrold_GPS { get; set; } //latitude,longtitue. If 0,0 then no gps tracking
public string patrold_takenGPS { get; set; } //filled by apps
public DateTime patrold_takenDateTime { get; set; } //filled by apps - scan date time
public string patrold_remark { get; set; } //filled by apps
}
Base View Model
public class BaseViewModel : INotifyPropertyChanged
#region INotifyPropertyChanged
public event PropertyChangedEventHandler PropertyChanged;
protected void OnPropertyChanged([CallerMemberName] string propertyName = "")
{
var handler = PropertyChanged;
handler?.Invoke(this, new PropertyChangedEventArgs(propertyName));
}
View Model
public string _patrold_remark;
public string patrold_remark
{
get { return _patrold_remark; }
set
{
_patrold_remark = value;
OnPropertyChanged();
}
}
public ObservableCollection<APIPatrolD> _DAPIPatrolDSiapImbasList;
public ObservableCollection<APIPatrolD> DAPIPatrolDSiapImbasList
{
get { return _DAPIPatrolDSiapImbasList; }
set
{
if (_DAPIPatrolDSiapImbasList != value)
{
_DAPIPatrolDSiapImbasList = value;
OnPropertyChanged();
}
}
}
public SecurityPortalDetailsPageViewModel(DAPIPatrolH dAPIPatrolH, int v)
{
DAPIPatrolDSiapImbasList = new ObservableCollection<APIPatrolD>();
}
private async void OnRemarksButtonClickedAsync(APIPatrolD obj)
{
// To Do display a customize PopUps=
var result = await App.Current.MainPage.Navigation.ShowPopupAsync(new CustomizePopups(obj));
foreach (APIPatrolD aPIPatrolD in DAPIPatrolDSiapImbasList) {
if (aPIPatrolD.patrold_loc == obj.patrold_loc) {
aPIPatrolD.patrold_remark = (string)result;
break;
}
}
OnPropertyChanged("DAPIPatrolDSiapImbasList");
}
UI Page
<CollectionView Grid.Row="2"
Grid.ColumnSpan="2"
ItemsSource="{Binding DAPIPatrolDSiapImbasList,Mode=TwoWay}">
<CollectionView.EmptyView>
<StackLayout>
<Label Text="Tiada Rekod" HorizontalOptions="CenterAndExpand" TextColor="Black" FontAttributes="Bold" FontSize="18" VerticalOptions="CenterAndExpand"/>
</StackLayout>
</CollectionView.EmptyView>
<CollectionView.ItemTemplate>
<DataTemplate>
<Grid Padding="10,5">
<Grid.ColumnDefinitions>
<ColumnDefinition Width="20"/>
<ColumnDefinition Width="0.5*"/>
<ColumnDefinition Width="1.2*"/>
<ColumnDefinition />
<ColumnDefinition Width="0.1"/>
</Grid.ColumnDefinitions>
<Grid.RowDefinitions>
<RowDefinition Height="55"/>
<RowDefinition Height="25"/>
<RowDefinition Height="25"/>
<RowDefinition Height="3" />
</Grid.RowDefinitions>
<Label FontSize="15" FontAttributes="Bold" Text="{Binding patrold_seq}" TextColor="#403f3f" VerticalOptions="CenterAndExpand" HorizontalOptions="CenterAndExpand"/>
<Label FontSize="15" FontAttributes="Bold" Grid.Column="1" Text="{Binding patrold_loc}" TextColor="#403f3f" VerticalOptions="CenterAndExpand" HorizontalOptions="StartAndExpand"/>
<Label FontSize="15" FontAttributes="Bold" Grid.Column="2" Text="{Binding patrold_desc}" TextColor="#403f3f" VerticalOptions="CenterAndExpand" HorizontalOptions="StartAndExpand"/>
<Label FontSize="15" FontAttributes="Bold" Grid.ColumnSpan="5" Grid.Row="1" Text="{Binding patrold_takenDateTime, StringFormat='{dd/MM/yy hh:mm tt}'}" TextColor="#403f3f" VerticalOptions="CenterAndExpand" HorizontalOptions="StartAndExpand"/>
<Label FontSize="15" FontAttributes="Bold" Grid.ColumnSpan="5" Grid.Row="2" x:Name="Remarks" Text="{Binding patrold_remark}" TextColor="#403f3f" VerticalOptions="CenterAndExpand" HorizontalOptions="StartAndExpand"/>
<Button Text="Pemerhatian" FontSize="9" FontAttributes="Bold" Grid.Column="3" BackgroundColor="Red" HeightRequest="30" WidthRequest="120" VerticalOptions="CenterAndExpand" HorizontalOptions="CenterAndExpand"
Command="{Binding Path=BindingContext.RemarksCommand, Source={x:Reference _SecurityPortalDetailsPage}}"
CommandParameter="{Binding .}"
TextTransform="None"
/>
<controls:CFrame Grid.Row="3" Grid.ColumnSpan="5" BackgroundColor="LightGray"/>
</Grid>
</DataTemplate>
</CollectionView.ItemTemplate>
</CollectionView>
Refer to the following code:
`
public class APIPatrolD:INotifyPropertyChanged
private string _patrold_loc;
public string patrold_loc {
get { return _patrold_loc; }
set {
_patrold_loc = value;
OnPropertyChanged("patrold_loc");
}
}
`

Unhandled Exception: System.InvalidCastException: Specified cast is not valid. when trying to save data to my database xamarin forms

Ok so heres the basic of my app : On opening im in the AcceuilPage.xaml, i click the + icon to add a new item to the collection.
Then it brings me to the NewFormPage.xaml which i use to fill a data form, then when i click save i call the SaveButtonClicked method from NewFormPage.xaml.cs BUT my app just crash and i get: Unhandled Exception: System.InvalidCastException: Specified cast is not valid. But i have no clue why ?
Thanks for your help !
Also, i tried this to see if data were created and everything was working fine :
private void CreateSampleData()
{
base.OnAppearing();
ObservableCollection<Agenda> list = new ObservableCollection<Agenda>();
list.Add(new Agenda { Topic = "Journée au chantier", Duration = "07:30 UTC - 11:30 UTC", Color = "#B96CBD", Date = new DateTime(2020, 3, 23) });
list.Add(new Agenda { Topic = "Journée au chantier", Duration = "07:30 UTC - 11:30 UTC", Color = "#B96CBD", Date = new DateTime(2020, 3, 23) });
AgendaCollection.ItemsSource = list;
}
Heres the code :
AgendaDatabase.cs in the Database folder
using System;
using System.Collections.Generic;
using System.Text;
using SQLite;
using Calculette.Models;
using System.Threading.Tasks;
namespace Calculette.Database
{
public class AgendaDatabase
{
readonly SQLiteAsyncConnection database;
public AgendaDatabase(string dbPath)
{
database = new SQLiteAsyncConnection(dbPath);
database.CreateTableAsync<Agenda>().Wait();
}
// Get all agenda
public Task<List<Agenda>> GetAgendasAsync()
{
return database.Table<Agenda>().ToListAsync();
}
// Get specific agenda
public Task<Agenda> GetAgendaAsync(int id)
{
return database.Table<Agenda>()
.Where(i => i.ID == id)
.FirstOrDefaultAsync();
}
// Insert new agenda (save)
public Task<int> SaveAgendaAsync(Agenda agenda)
{
if (agenda.ID != 0)
{
return database.UpdateAsync(agenda);
}
else
{
return database.InsertAsync(agenda);
}
}
//Delete specific agenda
public Task<int> DeleteAgendaAsync(Agenda agenda)
{
return database.DeleteAsync(agenda);
}
}
}
Agenda.cs in Models folder
using System;
using System.Collections.Generic;
using System.Collections.ObjectModel;
using System.Text;
using SQLite;
using Calculette.Database;
namespace Calculette.Models
{
public class Agenda
{
[PrimaryKey, AutoIncrement]
public int ID { get; set; }
public string Topic { get; set; }
public string Duration { get; set; }
public DateTime Date { get; set; }
}
}
NewFormPage.xaml in the views folder
<ContentPage.Content>
<StackLayout>
<StackLayout >
<Label Text="Date de calcul:" FontAttributes="Bold" FontFamily="ROBOTO" TextColor="#000000"></Label>
<DatePicker x:Name="Datepicker" Date="{Binding Date}" FontFamily="ROBOTO" Format="yyyy-MM-dd" ></DatePicker>
</StackLayout>
<StackLayout >
<Label Text="Description" FontAttributes="Bold" FontFamily="ROBOTO" TextColor="#000000"></Label>
<Entry x:Name="Description" Text="{Binding Topic}"/>
</StackLayout>
<StackLayout>
<Label Text="Durée quotidienne" FontAttributes="Bold" FontFamily="ROBOTO" TextColor="#000000"></Label>
<Entry x:Name="Duree" Placeholder="HH:MM:SS" Text="{Binding Duration}"/>
</StackLayout>
<StackLayout>
<Label Text="Niveau de pression dB(A)" FontAttributes="Bold" FontFamily="ROBOTO" TextColor="#000000"></Label>
<Entry x:Name="Pression" Text="{Binding Pression}"/>
</StackLayout>
<Editor Text="{Binding Commentary}"
x:Name="Commentary"
AutoSize="TextChanges"
Placeholder="Commentaires" />
<StackLayout>
<Button Text="Save" x:Name="SaveButton" TextColor="#008A00" BackgroundColor="#FFFFFF" BorderWidth="1" BorderColor="#1A961A" Clicked="SaveButtonClicked"></Button>
<ActivityIndicator IsRunning="{Binding IsBusy}"/>
</StackLayout>
</StackLayout>
</ContentPage.Content>
NewFormPage.xaml.cs in the views folder
using Calculette.Models;
using Calculette.ViewModel;
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using Xamarin.Forms;
using Xamarin.Forms.Xaml;
namespace Calculette.Views
{
[XamlCompilation(XamlCompilationOptions.Compile)]
public partial class NewFormPage : ContentPage
{
public NewFormPage ()
{
InitializeComponent ();
BindingContext = new FormViewModel();
}
async void SaveButtonClicked(object sender, EventArgs e)
{
var agenda = (Agenda)BindingContext;
//agenda.Date = DateTime.UtcNow;
await App.Database.SaveAgendaAsync(agenda);
await Navigation.PopAsync();
}
}
}
AcceuilPage.xaml
<ContentPage.Content>
<!-- ScrollView nous permet d'avoir une page scrollable-->
<ScrollView Orientation="Vertical">
<CollectionView Grid.Row="2" Margin="25" HorizontalOptions="FillAndExpand" VerticalOptions="FillAndExpand"
SelectionMode="None" x:Name="AgendaCollection"> <!--ItemsSource="{Binding AngedaCollection}" -->
<CollectionView.Header>
<StackLayout Orientation="Horizontal" Spacing="220">
<Label Text="Agenda" TextColor="Black" FontSize="18"/>
<ImageButton Source="iconplus.png" HeightRequest="30" WidthRequest="30" Clicked="GoToNewFormPage"></ImageButton>
</StackLayout>
</CollectionView.Header>
<CollectionView.ItemsLayout>
<LinearItemsLayout Orientation="Vertical" ItemSpacing="20"/>
</CollectionView.ItemsLayout>
<CollectionView.ItemTemplate >
<DataTemplate>
<pv:PancakeView HasShadow="True" BackgroundColor="White" VerticalOptions="StartAndExpand "
HorizontalOptions="FillAndExpand">
<Grid VerticalOptions="StartAndExpand" HorizontalOptions="FillAndExpand">
<Grid.ColumnDefinitions>
<ColumnDefinition Width="Auto"/>
<ColumnDefinition Width="*"/>
</Grid.ColumnDefinitions>
<BoxView BackgroundColor="{Binding Color}" WidthRequest="3" HorizontalOptions="Start"
VerticalOptions="FillAndExpand"/>
<Expander Grid.Column="1">
<Expander.Header>
<Grid HorizontalOptions="FillAndExpand">
<Grid.ColumnDefinitions>
<ColumnDefinition Width="*"/>
<ColumnDefinition Width="Auto"/>
<ColumnDefinition Width="3.5*"/>
</Grid.ColumnDefinitions>
<StackLayout HorizontalOptions="Center" VerticalOptions="Center">
<Label Text="{Binding Date, StringFormat='{0:dd}'}" TextColor="#008A00" FontSize="27"
HorizontalOptions="Center"/>
<Label Text="{Binding Date, StringFormat='{0:MMMM}'}" TextColor="Black" FontSize="10"
HorizontalOptions="Center" Margin="0,-10,0,0" FontAttributes="Bold"/>
<ImageButton Source="iconplus.png" HorizontalOptions="Center" HeightRequest="30" WidthRequest="30" Clicked="GoToFormPage"></ImageButton>
</StackLayout>
<BoxView Grid.Column="1" BackgroundColor="#F2F4F8" WidthRequest="1" HorizontalOptions="Start"
VerticalOptions="FillAndExpand"/>
<StackLayout Grid.Column="2" HorizontalOptions="Start" VerticalOptions="Center" Margin="20">
<Label Text="{Binding Topic}" TextColor="#008A00" FontSize="15" FontAttributes="Bold"/>
<Label Text="{Binding Duration}" TextColor="#2F3246" FontSize="12" Margin="0,-10,0,0"/>
</StackLayout>
</Grid>
</Expander.Header>
<Grid HorizontalOptions="FillAndExpand">
<Grid.ColumnDefinitions>
<ColumnDefinition Width="*"/>
<ColumnDefinition Width="Auto"/>
<ColumnDefinition Width="3.5*"/>
</Grid.ColumnDefinitions>
<BoxView Grid.Column="1" BackgroundColor="#F2F4F8" WidthRequest="1" HorizontalOptions="Start"
VerticalOptions="FillAndExpand"/>
<StackLayout Grid.Column="2" Spacing="10">
<Label Text="Tâches" TextColor="Black" FontSize="15" Margin="20,0"/>
<StackLayout BindableLayout.ItemsSource="{Binding Speakers}" HorizontalOptions="Start" VerticalOptions="Center" Margin="20,0,0,20">
<BindableLayout.ItemTemplate>
<DataTemplate>
<Label TextColor="#2F3246" FontSize="12">
<Label.FormattedText>
<FormattedString>
<FormattedString.Spans>
<Span Text="{Binding Time}"/>
<Span Text=" - "/>
<Span Text="{Binding Name}" FontAttributes="Bold"/>
</FormattedString.Spans>
</FormattedString>
</Label.FormattedText>
</Label>
</DataTemplate>
</BindableLayout.ItemTemplate>
</StackLayout>
</StackLayout>
</Grid>
</Expander>
</Grid>
</pv:PancakeView>
</DataTemplate>
</CollectionView.ItemTemplate>
</CollectionView>
</ScrollView>
</ContentPage.Content>
AcceuilPage.xaml.ca
public partial class MainPage : TabbedPage
{
public MainPage()
{
InitializeComponent();
this.BindingContext = this;
}
protected async void GoToFormPage(object sender, EventArgs e)
{
await Navigation.PushAsync(new Views.AgendaItemDetailPage());
}
protected async void GoToNewFormPage(object sender, EventArgs e)
{
await Navigation.PushAsync(new Views.NewFormPage());
}
protected override async void OnAppearing()
{
base.OnAppearing();
AgendaCollection.ItemsSource = await App.Database.GetAgendasAsync();
}
}
here, BindingContext is declared as a FormViewModel
public NewFormPage ()
{
InitializeComponent ();
BindingContext = new FormViewModel();
}
but here you are trying to cast BindingContext as an Agenda
async void SaveButtonClicked(object sender, EventArgs e)
{
var agenda = (Agenda)BindingContext;
//agenda.Date = DateTime.UtcNow;
await App.Database.SaveAgendaAsync(agenda);
await Navigation.PopAsync();
}

How to delete items from a collection view in xamarin.forms?

NOTE: this didn't work : SQLite Error: Cannot delete WhereListIterator`1: it has no PK
(Adding a table name made no change)
I have an AcceuilPage which basically do this : https://github.com/devcrux/Xamarin.Forms-Expander but i added a delete icon and when i press it i want to be able to delete all the content for this date ( also the date) from this page.
So i added a delete function to delete it from database but when i expand for a date and press delete i get this error : Exception:
System.NotSupportedException: Cannot delete Object: it has no PK which bring me to await App.Database.DeleteAgendaAsync(agenda); in :
async void DeleteButtonClicked(object sender, EventArgs e)
{
var agenda = (Agenda)AgendaCollection.SelectedItem;
await App.Database.DeleteAgendaAsync(agenda);
await Navigation.PopAsync();
}
i also tried for the error line this : await App.Database.DeleteAgendaAsync(agenda); but this didn't even do anything when i pressed it ( no error and nothing happening).
I saw that this was a working fine for a listview but im struggling to do it in a collectionview, feels to me like it doesn't know if i am currently selecting something. ( With listview, when u click an item, the item view change color).
What am i doing wrong, im also starting to think that using a listview would be more simple.
My AcceuilPage.xaml
<ContentPage.Content>
<!-- ScrollView nous permet d'avoir une page scrollable-->
<ScrollView Orientation="Vertical">
<CollectionView Grid.Row="2" Margin="25" HorizontalOptions="FillAndExpand" VerticalOptions="FillAndExpand"
SelectionMode="None" x:Name="AgendaCollection"> <!--ItemsSource="{Binding AngedaCollection}" -->
<CollectionView.Header>
<StackLayout Orientation="Horizontal" Spacing="220">
<Label Text="Agenda" TextColor="Black" FontSize="18"/>
<StackLayout Orientation="Horizontal">
<ImageButton Source="iconplus.png" HeightRequest="30" WidthRequest="30" Clicked="GoToNewFormPage"></ImageButton>
<ImageButton Source="iconmoins.png" HeightRequest="30" WidthRequest="30"></ImageButton>
</StackLayout>
</StackLayout>
</CollectionView.Header>
<CollectionView.ItemsLayout>
<LinearItemsLayout Orientation="Vertical" ItemSpacing="20"/>
</CollectionView.ItemsLayout>
<CollectionView.ItemTemplate >
<DataTemplate>
<pv:PancakeView HasShadow="True" BackgroundColor="White" VerticalOptions="StartAndExpand "
HorizontalOptions="FillAndExpand">
<Grid VerticalOptions="StartAndExpand" HorizontalOptions="FillAndExpand">
<Grid.ColumnDefinitions>
<ColumnDefinition Width="Auto"/>
<ColumnDefinition Width="*"/>
</Grid.ColumnDefinitions>
<BoxView BackgroundColor="{Binding Color}" WidthRequest="3" HorizontalOptions="Start"
VerticalOptions="FillAndExpand"/>
<Expander Grid.Column="1" >
<Expander.Header>
<Grid HorizontalOptions="FillAndExpand">
<Grid.ColumnDefinitions>
<ColumnDefinition Width="*"/>
<ColumnDefinition Width="Auto"/>
<ColumnDefinition Width="3.5*"/>
</Grid.ColumnDefinitions>
<StackLayout HorizontalOptions="Center" VerticalOptions="Center">
<Label Text="{Binding Date, StringFormat='{0:dd}'}" TextColor="#008A00" FontSize="27"
HorizontalOptions="Center"/>
<Label Text="{Binding Date, StringFormat='{0:MMMM}'}" TextColor="Black" FontSize="10"
HorizontalOptions="Center" Margin="0,-10,0,0" FontAttributes="Bold"/>
<ImageButton Source="iconplus.png" HorizontalOptions="Center" HeightRequest="30" WidthRequest="30" Clicked="GoToFormPage"></ImageButton>
</StackLayout>
<BoxView Grid.Column="1" BackgroundColor="#F2F4F8" WidthRequest="1" HorizontalOptions="Start"
VerticalOptions="FillAndExpand"/>
<StackLayout x:Name="topicLayout" Grid.Column="2" HorizontalOptions="Start" VerticalOptions="Center" Margin="20">
<Label Text="{Binding Topic}" TextColor="#008A00" FontSize="15" FontAttributes="Bold"/>
<Label Text="{Binding Duration}" TextColor="#2F3246" FontSize="12" Margin="0,-10,0,0"/>
<ImageButton Source="iconmoins.png" HeightRequest="30" WidthRequest="30" Clicked="DeleteButtonClicked"></ImageButton>
</StackLayout>
</Grid>
</Expander.Header>
<Grid HorizontalOptions="FillAndExpand">
<Grid.ColumnDefinitions>
<ColumnDefinition Width="*"/>
<ColumnDefinition Width="Auto"/>
<ColumnDefinition Width="3.5*"/>
</Grid.ColumnDefinitions>
<BoxView Grid.Column="1" BackgroundColor="#F2F4F8" WidthRequest="1" HorizontalOptions="Start"
VerticalOptions="FillAndExpand"/>
<StackLayout Grid.Column="2" Spacing="10">
<Label Text="Tâches" TextColor="Black" FontSize="15" Margin="20,0"/>
<StackLayout BindableLayout.ItemsSource="{Binding Speakers}" HorizontalOptions="Start" VerticalOptions="Center" Margin="20,0,0,20">
<BindableLayout.ItemTemplate>
<DataTemplate>
<Label TextColor="#2F3246" FontSize="12">
<Label.FormattedText>
<FormattedString>
<FormattedString.Spans>
<Span Text="{Binding Time}"/>
<Span Text=" - "/>
<Span Text="{Binding Name}" FontAttributes="Bold"/>
</FormattedString.Spans>
</FormattedString>
</Label.FormattedText>
</Label>
</DataTemplate>
</BindableLayout.ItemTemplate>
</StackLayout>
</StackLayout>
</Grid>
</Expander>
</Grid>
</pv:PancakeView>
</DataTemplate>
</CollectionView.ItemTemplate>
</CollectionView>
</ScrollView>
</ContentPage.Content>
My AcceuilPage.xaml.cs
using Calculette.ViewModel;
using Calculette.Models;
using System;
using System.Collections.Generic;
using System.Collections.ObjectModel;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using Xamarin.Forms;
using Xamarin.Forms.PancakeView;
namespace Calculette
{
public partial class MainPage : TabbedPage
{
public MainPage()
{
InitializeComponent();
BindingContext = new Agenda();
}
protected async void GoToFormPage(object sender, EventArgs e)
{
await Navigation.PushAsync(new Views.AgendaItemDetailPage());
}
protected async void GoToNewFormPage(object sender, EventArgs e)
{
await Navigation.PushAsync(new Views.NewFormPage());
}
async void DeleteButtonClicked(object sender, EventArgs e)
{
var agenda = (Agenda)BindingContext;
await App.Database.DeleteAgendaAsync(agenda);
await Navigation.PopAsync();
}
protected override async void OnAppearing()
{
base.OnAppearing();
AgendaCollection.ItemsSource = await App.Database.GetAgendasAsync();
}
}
}
AgendaDatabase.cs
using System;
using System.Collections.Generic;
using System.Text;
using SQLite;
using Calculette.Models;
using System.Threading.Tasks;
namespace Calculette.Database
{
public class AgendaDatabase
{
readonly SQLiteAsyncConnection database;
public AgendaDatabase(string dbPath)
{
database = new SQLiteAsyncConnection(dbPath);
database.CreateTableAsync<Agenda>().Wait();
}
// Get all agenda
public Task<List<Agenda>> GetAgendasAsync()
{
return database.Table<Agenda>().ToListAsync();
}
// Get specific agenda
public Task<Agenda> GetAgendaAsync(int id)
{
return database.Table<Agenda>()
.Where(i => i.ID == id)
.FirstOrDefaultAsync();
}
// Insert new agenda (save)
public Task<int> SaveAgendaAsync(Agenda agenda)
{
if (agenda.ID != 0)
{
return database.UpdateAsync(agenda);
}
else
{
return database.InsertAsync(agenda);
}
}
//Delete specific agenda
public Task<int> DeleteAgendaAsync(Agenda agenda)
{
return database.DeleteAsync(agenda);
}
}
}
Agenda.cs
using System;
using System.Collections.Generic;
using System.Collections.ObjectModel;
using System.Text;
using SQLite;
using Calculette.Database;
namespace Calculette.Models
{
[Table("Agenda")]
public class Agenda
{
[PrimaryKey, AutoIncrement]
public int ID { get; set; }
public string Topic { get; set; }
public string Duration { get; set; }
public DateTime Date { get; set; }
}
}
When we touch on the imagebutton/button , the click event triggers , but it does not mean we select an item in CollectionView ,the button click event covers the click/tap event on item of Collectionview itself, so in this scenario , AgendaCollection.SelectedItem is null ,then the error happens .
For the second approach you used: var agenda = (Agenda)BindingContext; , you set BindingContext in constructor : BindingContext = new Agenda(); , BindingContext is a brand new object which is not the one you are selecting .
To solve the prorblem , you could get the imagebutton's BindingContext and then manipulate the logic .
async void DeleteButtonClicked(object sender, EventArgs e)
{
ImageButton button = sender as ImageButton;
var agenda = button.BindingContext as Agenda;
await App.Database.DeleteAgendaAsync(agenda);
await Navigation.PopAsync();
}
Update
public ObservableCollection<Agenda> GetAgendasAsync()
{
List<Agenda>list = database.Table<Agenda>().ToListAsync().Result;
ObservableCollection<Agenda> result = new ObservableCollection<Agenda>(list);
return result;
}

xamarin.forms listview Items only update when scrolling even after iNotifyPropertychanged implementation

I have a xamarin.forms app which have a listview showing item fetched from firebase. The issue I am facing is well asked question in SO ie; one of my item in listview (an item named location ) only updates when we scroll the listview. I tried to implement the iNotifyPropertychanged but still I am facing the same issue. What is the mistake I am doing here? Any help is appriciated.
My Listview Itemsource setting
var person = await firebaseHelper.GetPerson(EmployeeID);// getting data from firebase
LocationData = person.userdata.Where(x => DateTime.Parse(x.DateTime).ToString("yyyy-MM-dd") == StartDate.Date.ToString("yyyy-MM-dd") && x.Longitude != "initial").ToList();
ObservableCollection<UserLocationData> dynamicLocation = new ObservableCollection<UserLocationData>(LocationData);
TrackingListView.ItemsSource = dynamicLocation;
if (dynamicLocation.Count != 0)
{
foreach (UserLocationData Item in dynamicLocation)
{
Item.DateTime = DateTime.Parse(Item.DateTime).ToString("MMMM dd,yyyy hh:mm tt");
if (!string.IsNullOrEmpty(Item.Latitude) && !string.IsNullOrEmpty(Item.Longitude))
{
var Locations = await Geocoding.GetPlacemarksAsync(Convert.ToDouble(Item.Latitude), Convert.ToDouble(Item.Longitude));
var placemark = Locations?.FirstOrDefault();
if (placemark.Thoroughfare.ToString() != null)
{
var geocodeAddress =
placemark.Thoroughfare + '\n' +
placemark.SubAdminArea + '\n';
Item.Location = geocodeAddress.ToString();
}
else
{
Item.Location = Item.Latitude + "," + Item.Longitude;
}
}
}
My Datamodel
public class Person : INotifyPropertyChanged
{
public event PropertyChangedEventHandler PropertyChanged;
private void NotifyPropertyChanged([CallerMemberName] String propertyName = "")
{
PropertyChanged?.Invoke(this, new PropertyChangedEventArgs(propertyName));
}
public string Name { get; set; }
public string PersonId { get; set; }
public string Address { get; set; }
public string PhoneNumber { get; set; }
public string EmailID { get; set; }
public string Password { get; set; }
public bool Status { get; set; }
public bool IsAdmin { get; set; }
public List<UserLocationData> userdata { get; set; }
}
public partial class UserLocationData : INotifyPropertyChanged
{
public event PropertyChangedEventHandler PropertyChanged;
private void NotifyPropertyChanged([CallerMemberName] String propertyName = "")
{
PropertyChanged?.Invoke(this, new PropertyChangedEventArgs(propertyName));
}
public string Latitude { get; set; }
public string Longitude { get; set; }
public string DateTime { get; set; }
private string _location;
public string Location
{
get
{
return _location;
}
set
{
if (value != null)
{
_location = value;
NotifyPropertyChanged("Selected");
}
}
}
public bool ButtonOn { get; set; }
public bool ButtonOff { get; set; }
}
The Firebase GetPerson portion
public async Task<Person> GetPerson(string personId)
{
var allPersons = await GetAllPersons();
await firebase
.Child("Persons")
.OnceAsync<Person>();
return allPersons.Where(a => a.PersonId == personId).FirstOrDefault();
}
My XAML
<ListView x:Name="TrackingListView" ItemsSource="{Binding} "
HasUnevenRows="True"
IsVisible="False"
CachingStrategy="RecycleElement"
SeparatorVisibility="None"
SelectionMode="None"
BackgroundColor="Transparent"
Margin="10,10,10,10"
HorizontalOptions="FillAndExpand"
>
<ListView.ItemTemplate>
<DataTemplate>
<ViewCell>
<ViewCell.View>
<Frame
Padding="5"
Margin="0,5,0,5"
Opacity="0.9"
BackgroundColor="White"
BorderColor="LightBlue"
HasShadow="True"
CornerRadius="10"
ClassId="{Binding DateTime}"
HorizontalOptions="FillAndExpand">
<Frame.GestureRecognizers>
<TapGestureRecognizer Tapped="TapGestureRecognizer_Tapped"></TapGestureRecognizer>
</Frame.GestureRecognizers>
<Grid Margin="0,10,0,0" >
<Grid.RowDefinitions>
<RowDefinition Height="Auto"/>
<RowDefinition Height="Auto"/>
<RowDefinition Height="Auto"/>
</Grid.RowDefinitions>
<Grid.ColumnDefinitions>
<ColumnDefinition Width="*"/>
<ColumnDefinition Width="Auto"/>
</Grid.ColumnDefinitions>
<StackLayout HorizontalOptions="FillAndExpand" Grid.Row="0" Grid.Column="0" Orientation="Horizontal">
<Image Source="clock.png" HorizontalOptions="Start" VerticalOptions="Start"
HeightRequest="20" Margin="10,0,5,0"
></Image>
<StackLayout Orientation="Vertical" Margin="0" HorizontalOptions="FillAndExpand">
<Label Text="Location fetched time" FontSize="12" HorizontalOptions="StartAndExpand" VerticalOptions="Center"
TextColor="Blue"
></Label>
<Label Text="{Binding DateTime}" HorizontalOptions="StartAndExpand" VerticalOptions="Center"
TextColor="Black" FontSize="Small"
></Label>
</StackLayout>
</StackLayout>
<StackLayout Grid.Column="1" Grid.Row="0" HorizontalOptions="EndAndExpand" VerticalOptions="FillAndExpand">
<Image Source="googlemap.png" HorizontalOptions="End" VerticalOptions="Center" HeightRequest="30" ></Image>
</StackLayout>
<StackLayout HorizontalOptions="FillAndExpand" Grid.Row="1" Grid.Column="0" Grid.ColumnSpan="2" Orientation="Horizontal">
<Image Source="currentlocation.png" HorizontalOptions="Start" VerticalOptions="Start"
HeightRequest="20" Margin="10,0,5,0"
></Image>
<StackLayout Orientation="Vertical" Margin="0" HorizontalOptions="FillAndExpand">
<Label Text="Location " FontSize="12" HorizontalOptions="StartAndExpand" VerticalOptions="Center"
TextColor="Blue"
></Label>
<Label Text="{Binding Location}" HorizontalOptions="StartAndExpand" VerticalOptions="Center"
TextColor="Black" FontSize="Small"
></Label>
</StackLayout>
</StackLayout>
<StackLayout Grid.Row="2" Grid.Column="0" Grid.ColumnSpan="2" Margin="0" >
<Grid>
<StackLayout Orientation="Horizontal" Margin="0" IsVisible="{Binding ButtonOn}">
<Image Source="start.png" HorizontalOptions="Start"
HeightRequest="20" Margin="10,0,5,0"
VerticalOptions="Start">
</Image>
<Label Text="Location Tracking Started" VerticalOptions="Center" TextColor="Green" FontSize="12" ></Label>
</StackLayout>
<StackLayout Orientation="Horizontal" Margin="0" IsVisible="{Binding ButtonOff}">
<Image Source="stop.png" HorizontalOptions="Start"
HeightRequest="20" Margin="10,0,5,0"
VerticalOptions="Start">
</Image>
<Label Text="Location Tracking Stopped" VerticalOptions="Center" TextColor="Red" FontSize="12" ></Label>
</StackLayout>
</Grid>
</StackLayout>
</Grid>
</Frame>
</ViewCell.View>
</ViewCell>
</DataTemplate>
</ListView.ItemTemplate>
</ListView>
NotifyPropertyChanged("Selected"); it should be NotifyPropertyChanged("Location");

Resources