Search code examples
listviewxamarinakavache

Problem of Xamarin.Form (ListView not refresh if binding from Akavache cache)


I met a problem with refresh list.

I'm using MasterDetailPage with init default in Visual Studio 2019 (Xamarin.Forms 4.3.0.991250) & Akavache 6.6.1, has a variable is Items of type ObservableCollection<TodoItem>.

The first, i added one item to cache (i call this object is TodoItem). And then show ListView with Items binding got from Akavache cache, but it's not working, Items has values -> ListView not refresh.

I tried with something:

  • Change version (Xamarin.Forms & Akavache), Ex: XF 4.1 highest version and akavache downgrade 6.0, 6.1, 6.2... => not working.

  • If setup Items with hardcode new ObservableCollection(new ListView(){ ... }) => it's working.

  • If app running, i change something on the layout and save (Xaml hot reload) -> it's working.

    public ObservableCollection Items { get; set; } = new ObservableCollection();

    #region AddNewCommand
    
    private Command _addNewCommand;
    
    public Command AddNewCommand =>
        _addNewCommand ?? (_addNewCommand = new Command(async (p) => await AddNewExecute(), (p) => !IsBusy));
    
    private async Task AddNewExecute()
    {
        var key = Guid.NewGuid().ToString().Substring(0, 5);
        await BlobCache.LocalMachine.InsertObject<TodoItem>(key, new TodoItem() {Id=key.Substring(0,2),Text="abc",Description="def" }, new TimeSpan(1, 0, 0));
        var list = await BlobCache.LocalMachine.GetAllObjects<TodoItem>();
        Items = new ObservableCollection<TodoItem>(list);
    }
    #endregion
    

Solution

  • In order to make a change to a variable bindend to the UI you have to do it inside BeginInvokeOnMainThread

    Something like this:

    private async Task AddNewExecute()
    {
         var key = Guid.NewGuid().ToString().Substring(0, 5);
         await BlobCache.LocalMachine.InsertObject<TodoItem>(key, new TodoItem() 
            {
              Id=key.Substring(0,2),Text="abc",Description="def" }, new TimeSpan(1, 0, 0));
              Device.BeginInvokeOnMainThread (async () => {
              var list = await BlobCache.LocalMachine.GetAllObjects<TodoItem>();
              Items = new ObservableCollection<TodoItem>(list);
            });
    }
    

    In this way you're changing the variable on the UI thread