Hello everyone
I have my basic app ready, but I have a few bugs. I am using MVVM, which state "No code-behind" (This is difficult because when yoy pass objects to another page, to need to catch them somehow)
Anyway, I am trying to delete Contacts from my DB, the contact will get deleted when I press delete, but the UI doesn't update, I have to reset the app to see the changes.
What I am doing wrong
Contacts UI
<ContentPage.ToolbarItems>
<ToolbarItem Text="New contact"
Command="{x:Binding AddContact}" />
</ContentPage.ToolbarItems>
<ContentPage.BindingContext>
<vm:ContactsVM />
</ContentPage.BindingContext>
<ContentPage.Resources>
<Style TargetType="cards:SfCardView">
<Setter Property="VisualStateManager.VisualStateGroups">
<VisualStateGroupList>
<VisualStateGroup x:Name="CommonStates">
<VisualState x:Name="Normal" />
<VisualState x:Name="Selected">
<VisualState.Setters>
<Setter Property="BackgroundColor"
Value="LightSkyBlue" />
</VisualState.Setters>
</VisualState>
</VisualStateGroup>
</VisualStateGroupList>
</Setter>
</Style>
</ContentPage.Resources>
<CollectionView ItemsSource="{x:Binding Contacts}"
SelectedItem="{x:Binding SelectedItem}"
SelectionChangedCommand="{x:Binding SelectionItemCommand}"
SelectionMode="Single">
<CollectionView.ItemTemplate>
<DataTemplate>
<cards:SfCardView CornerRadius="5"
BackgroundColor="CornflowerBlue"
Margin="10,10,10,10"
Padding="10">
<StackLayout>
<Label Text="{x:Binding Name, StringFormat='Name: {0}'}"
FontSize="14"
FontAttributes="Bold"/>
<Label Text="{x:Binding PhoneNumber, StringFormat='Phone: {0}'}"
Grid.Row="1"
FontSize="10"/>
<Label Text="{x:Binding Address, StringFormat='Address: {0}'}"
Grid.Row="2"
FontSize="10"/>
</StackLayout>
</cards:SfCardView>
</DataTemplate>
</CollectionView.ItemTemplate>
</CollectionView>
Model
public class Contact : ViewModelBase {
[PrimaryKey, AutoIncrement]
public int Id { get; set; }
private string _Name;
public string Name {
get { return _Name; }
set {
if (_Name != value) {
_Name = value;
RaisePropertyChanged();
}
}
}
private string _PhoneNumber;
public string PhoneNumber {
get { return _PhoneNumber; }
set {
if (_PhoneNumber != value) {
_PhoneNumber = value;
RaisePropertyChanged();
}
}
}
private string _Address;
public string Address {
get { return _Address; }
set {
if (_Address != value) {
_Address = value;
RaisePropertyChanged();
}
}
}
}
}
View Model Base
public class ViewModelBase : INotifyPropertyChanged {
#region Notify Property Changed Members
public event PropertyChangedEventHandler PropertyChanged;
protected void RaisePropertyChanged([CallerMemberName] string propertyName = "") {
PropertyChanged?.Invoke(this, new PropertyChangedEventArgs(propertyName));
}
#endregion
}
DB Helper
namespace ContactXam.Service {
public class DBHelper {
static SQLiteAsyncConnection db;
static async Task init() {
if (db != null) {
return;
}
var databasePath = Path.Combine(FileSystem.AppDataDirectory, "MyContacts.db");
db = new SQLiteAsyncConnection(databasePath);
await db.CreateTableAsync<Person>();
}
public static async Task AddContact(string name, string phoneNumber, string address) {
await init();
Person person = new Person() {
Name = name,
PhoneNumber = phoneNumber,
Address = address
};
var id = await db.InsertAsync(person);
}
public static async Task removeContact(int id) {
await init();
await db.DeleteAsync<Person>(id);
}
public static async Task<List<Person>> getContacts() {
await init();
var personList = await db.Table<Person>().ToListAsync();
return personList;
}
}
}
Contacts VM
public ICommand AddContact { get; set; }
private ObservableCollection<Person> _Contacts;
public ObservableCollection<Person> Contacts {
get { return _Contacts; }
set {
if (_Contacts != value) {
_Contacts = value;
RaisePropertyChanged();
}
}
}
private Person _SelectedItem;
public Person SelectedItem {
get { return _SelectedItem; }
set {
if (_SelectedItem != value) {
_SelectedItem = value;
RaisePropertyChanged();
}
}
}
public ICommand SelectionItemCommand { get; set; }
public ContactsVM() {
Populatedatabase();
AddContact = new Command(async () => {
var mainPage = Application.Current.MainPage;
await mainPage.Navigation.PushAsync(new AddContact());
});
SelectionItemCommand = new Command(async () => {
if (SelectedItem != null) {
var mainPage = Application.Current.MainPage;
string action = await mainPage.DisplayActionSheet(
"What do you want to do?:", "Cancel", "Delete", "Call", "Update", string.Empty);
Debug.WriteLine("Action: " + action);
switch (action) {
case "Call":
var status = await Xamarin.Essentials.
Permissions.RequestAsync<Xamarin.Essentials.Permissions.Phone>();
if (status != Xamarin.Essentials.PermissionStatus.Granted) {
status = await Xamarin.Essentials.
Permissions.RequestAsync<Xamarin.Essentials.Permissions.Phone>();
}
var phoneDialer = CrossMessaging.Current.PhoneDialer;
if (phoneDialer.CanMakePhoneCall)
phoneDialer.MakePhoneCall(SelectedItem.PhoneNumber);
break;
case "Update":
//await mainPage.Navigation.PushAsync(new UdateContactPage());
break;
case "Delete":
Contacts.Remove(SelectedItem);
await DBHelper.removeContact(SelectedItem.Id);
break;
default:
break;
}
SelectedItem = null;
}
});
}
public async void Populatedatabase() {
Contacts = new ObservableCollection<Person>();
var peopleList = await DBHelper.getContacts();
Contacts.Clear();
foreach (var item in peopleList) {
Contacts.Add(item);
}
}
}
}
UI part for adding the contact
<ContentPage.BindingContext>
<vm:AddContactVM />
</ContentPage.BindingContext>
<ContentPage.Content>
<Grid RowDefinitions="250, Auto"
RowSpacing="20">
<StackLayout BackgroundColor="AliceBlue">
<Image Source="User" HeightRequest="200" WidthRequest="200" VerticalOptions="CenterAndExpand" />
</StackLayout>
<StackLayout Grid.Row="1"
Margin="20">
<Entry Placeholder="Name"
Text="{x:Binding Contact.Name}" />
<Entry Placeholder="Phone Number"
Text="{x:Binding Contact.PhoneNumber}"
Keyboard="Numeric"
MaxLength="10"/>
<Entry Placeholder="Address"
Text="{x:Binding Contact.Address}" />
<Button Grid.Row="2"
Margin="40"
Command="{x:Binding SaveCommand}"
Text="Save"/>
</StackLayout>
</Grid>
</ContentPage.Content>
</ContentPage>