question

EduardoGomez-1870 avatar image
0 Votes"
EduardoGomez-1870 asked EduardoGomez-1870 commented

SQLite update UI in realtime

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>

dotnet-xamarinformsdotnet-sqlite
5 |1600 characters needed characters left characters exceeded

Up to 10 attachments (including images) can be used with a maximum of 3.0 MiB each and 30.0 MiB total.

1 Answer

JessieZhang-2116 avatar image
1 Vote"
JessieZhang-2116 answered EduardoGomez-1870 commented

Hello,


Welcome to our Microsoft Q&A platform!

When you tried to delete the seleted item by the following code, you can also try to remove the item form the Contacts . Since the type of Contacts is ObservableCollection<Contact> , once you delete the item from the Contacts , the UI will updated automatically.So you can remove the seleted item after you delete in your database.

     case "Delete":
                      using (SQLiteConnection sQLiteConnection = new SQLiteConnection(App.DatabaseLocation)) {
                          sQLiteConnection.CreateTable<Contact>();
                          int row = sQLiteConnection.Delete(SelectedItem);
                          if (row > 0) {
                              await mainPage.DisplayAlert("Deleted", "Element has been deleted successfully", "OK");
                          }

                         // delete the selected item in `Contacts `, then the UI will updated automatically.

                        
                      }
                      break;

In addition, I don't understand why you call 'ContactsVM = new ContactsVM(); 'to create a ContactsVM object and call function Populatedatabase() in method OnAppearing() on page ContactsPage . And I have found you have called function Populatedatabase(); in your ContactsVM.

If I understand correctly, So you can set BindingContext for your page and set the ItemsSource for control to Contacts :

      public partial class MainViewXaml : ContentPage
 {
    
  public ContactsVM contactsVM { get; set; }
    
 public MainViewXaml ()
 {
                        InitializeComponent();
    
 contactsVM = new ContactsVM ();
 BindingContext = contactsVM ;
 }
    } 

And in your ContactsPage.xaml , set the ItemsSource for your ListView to Contacts

    <ListView  x:Name="lstView"   ItemsSource="{Binding Contacts }"  >
    </ListView>


Update 1:

You can refer to the following code in my demo:

In the new contact page, , we can send a message to the contact list page :

         async void OnSaveClick(object sender, EventArgs e)
     {
         NewsarticleElements topicText = new NewsarticleElements();
         topicText.topicTitle = TopicTitle.Text;
         topicText.articleText = ArticleText.Text;


         MessagingCenter.Send(this, "AddItem", topicText);
         //await Navigation.PopAsync();
         await Navigation.PopModalAsync();
     }

And in the contact list page, we can Subscribe message as follows(my page is MainPage):

        public MainPage()
     {
         InitializeComponent();

         //BindingContext = new MainPageViewModel();

          MessagingCenter.Subscribe<NewPage, NewsarticleElements>(this, "AddItem", (obj, item) =>
         {

             var newItem = item as NewsarticleElements;
             NewItem temp = new NewItem() { NewsName= newItem.topicTitle, ArticleText= newItem.articleText };

             NewsItemList.Add(temp);

             NewsView.ItemsSource = null;
             NewsView.ItemsSource = NewsItemList;

         });
     }

Update 2

You can try the following code:

1.In ContactsVM.cs, Subscribe message in the constructor of class ContactsVM :

             public ContactsVM() {
             Populatedatabase();
    
             AddContact = new Command(async () => {
                 var mainPage = Application.Current.MainPage;
                 await mainPage.Navigation.PushAsync(new AddContact());
             });
    
    
             MessagingCenter.Subscribe<AddContactVM, Person>(this, "AddItem", (obj, item) =>
             {
                 Person newItem = item as Person;
    
                 Contacts.Add(newItem);
    
             });
    
      // other code
    
    }

2.send message in the constructor of class AddContactVM :

        public AddContactVM() {

         person = new Person();

         SaveCommand = new Command(async () => {

             await DBHelper.AddContact(person.Name, person.PhoneNumber, person.Address);


             // send message here
             MessagingCenter.Send<AddContactVM, Person>(this, "AddItem", person);


             var main = Application.Current.MainPage;

             await main.Navigation.PopAsync();

         });
     }



Best Regards,

Jessie Zhang


If the response is helpful, please click "Accept Answer" and upvote it.


Note: Please follow the steps in our documentation to enable e-mail notifications if you want to receive the related email notification for this thread.



· 22
5 |1600 characters needed characters left characters exceeded

Up to 10 attachments (including images) can be used with a maximum of 3.0 MiB each and 30.0 MiB total.

I updated the code I removed the binding context from the Code-Behind, and bind the list with the VM, but it doesn't add t my contacts realtime, but It will display my contacts and delete perfectly

0 Votes 0 ·

It doesn't add anywhere

0 Votes 0 ·

I am sorry I can confirm that it adds successfully, but not in realtime, I have to reset

0 Votes 0 ·
Show more comments