Forum Xamarin Xamarin.Forms

Xamarin.Essentials Preferences do not work anymore (debug mode)

galactosegalactose Member ✭✭
edited April 26 in Xamarin.Forms

Hi,

I had some trouble with a piece of code which was not working (my bad), and I restored it successfully. This code uses Preferences from Xamarin Essentials, and as I thought the problem was with it, I updated it with NuGet in the whole solution.

But now my problem is fixed, and I still face an issue that I can't resolve... The code works because I made tests, but I am not able to retrieve preferences at startup. Yet, preferences are correctly set at runtime, I checked its value in the app !

So, is it a known issue with Preferences ? It does not work in debug mode, neither release mode...

Precision : as I changed this piece of code to make it smarter and to preserve MVVM, I already tested Preferences and it worked very well even in debug mode... But as I updated it before being able to build again, I can't compare...

Thanks,
Galactose

(In case it's not a known issue, here is my code:

using System.Collections.ObjectModel;
using System.Collections.Specialized;
using System.Linq;
using Xamarin.Essentials;
using CardioCALC.Models;

namespace CardioCALC.ViewModels
{
    public sealed class FavoritesViewModel : ViewModelBase
    {
        /*
         *  SINGLETON :
         *      - Instance
         *      - Constructors to avoir other instance and be thread-safe
         */
        public static FavoritesViewModel Instance { get; } = new FavoritesViewModel();

        static FavoritesViewModel()
        { }

        private FavoritesViewModel()
        {
            this.Favorites.CollectionChanged += OnFavoritesSaveChanges; // Autosave
        }


        /*
         *  CLASS : classic properties and methodes to be used in the singleton instance
         *      - separator : constant char for serialization/deserialization
         *      - favoritePreferenceKey : constant string to be used as Key in Xamarin.Essentials.Preferences
         *      - Methods to Add/Remove/Toggle favorites (update list AND the score instance)
         */

        private const char separator = ',';
        private const string favoritePreferenceKey = "favorites";

        public ObservableCollection<Score> Favorites { get; private set; } = new ObservableCollection<Score>();
        public ObservableCollection<Score> Scores { get => ScoreListViewModel.Instance.Scores; }

        public void ToggleFavorite(Score score)
        {
            if (score.IsFavorite) this.RemoveFavoriteAndUpdate(score);
            else this.AddFavoriteAndUpdate(score);
        }

        public void AddFavoriteAndUpdate(Score score)
        {
            score.IsFavorite = true;
            if (!this.Favorites.Contains(score)) this.Favorites.AddSorted(score);
        }

        public void RemoveFavoriteAndUpdate(Score favorite)
        {
            favorite.IsFavorite = false;
            this.Favorites.Remove(favorite);
        }

        // Auto-save favorites list with event
        private void OnFavoritesSaveChanges(object sender, NotifyCollectionChangedEventArgs e)
        {
            this.SaveFavorites();
        }


        /*
         *      Methods to Save/Load favorites from database/preferences(with serialization/deserialization)
         */
        public void LoadSavedFavorites()
        {
            this.Favorites.Clear(); // Clear favorites (ie. to reload favorites after locale change in ScoreListViewModel)

            string favorites = Preferences.Get(favoritePreferenceKey, "");
            if (favorites == "") return;

            foreach (Score favorite in this.Deserialize(favorites))
            {
                this.AddFavoriteAndUpdate(favorite);
            }
        }

        public void SaveFavorites()
        {
            if (this.Favorites.Count > 0)
                Preferences.Set(favoritePreferenceKey, this.Serialize());

            else Preferences.Remove(favoritePreferenceKey);
        }

        // Serialize favorites list into string format
        public string Serialize()
        {
            if (this.Favorites.Count < 1) return "";

            string favorites = "";
            foreach (Score favorite in this.Favorites)
            {
                favorites += $"{favorite.PageName}{separator}";
            }
            return favorites.TrimEnd(separator);
        }

        // Deserialize favorites list from string to restore Collection
        public ObservableCollection<Score> Deserialize(string favorites)
        {
            ObservableCollection<Score> favoritesList = new ObservableCollection<Score>();
            foreach(string favorite in favorites.Split(separator))
            {
                favoritesList.Add(this.Scores.FirstOrDefault(s => s.PageName == favorite)); // this.Scores contains all scores
            }
            return favoritesList;
        }
    }
}

Best Answer

  • galactosegalactose Member ✭✭
    edited May 1 Accepted Answer

    Hi,

    Sorry for the time it took. I finally solved my error ! (so, no trouble with Xamarin.Essentials that I successfully tested with the same version in another project...)

    To issue was with:

    namespace CardioCALC.ViewModels
    {
        public sealed class FavoritesViewModel : ViewModelBase
        {
            /* ...... */
    
            private FavoritesViewModel()
            {
                this.Favorites.CollectionChanged += OnFavoritesSaveChanges; // Autosave
            }
    
            // Auto-save favorites list with event
            private void OnFavoritesSaveChanges(object sender, NotifyCollectionChangedEventArgs e)
            {
                this.SaveFavorites();
            }
    
            public void SaveFavorites()
            {
                if (this.Favorites.Count > 0)
                    Preferences.Set(favoritePreferenceKey, this.Serialize());
    
                else Preferences.Remove(favoritePreferenceKey);
            }
        }
    }
    

    Which has to be:

            private void OnFavoritesSaveChanges(object sender, NotifyCollectionChangedEventArgs e)
            {
                if (e.Action == NotifyCollectionChangedAction.Add || e.Action == NotifyCollectionChangedAction.Remove)
                    this.SaveFavorites();
            }
    

    Otherwise, the Clear() call in my LoadSavedFavorites() method was erasing the Xamarin.Essentials.Preferences key !! This Clear() call is needed as I call LoadSavedFavorites() when the locale changes, so that all Score objects with new localized labels have their IsFavorite property set correctly.

    Thanks for your time,
    Galactose

Answers

  • LandLuLandLu Member, Xamarin Team Xamurai

    Preferences is used to store some simple values.
    I noticed the string you stored is converted from a list. If the list has large items this could be subpar:
    https://docs.microsoft.com/en-us/xamarin/essentials/preferences?tabs=ios#limitations
    Have you tried it with a small string value?
    If you want to store a set of characters I suggest using

    File.WriteAllText(string path, string contents);
    

    Try this API to retrieve the local storage path:

    Environment.GetFolderPath(Environment.SpecialFolder.MyDocuments);
    
  • galactosegalactose Member ✭✭
    Yes I tried to store just one favorite so it is a very simple string like "HasBled". But when I ask at startup - from MainPage - what is Preferences.Get("favorites", "nothing"), the value is always "nothing".

    The simplest thing I tried:
    - Build app and set preferences so that "favorites" has just 1 simple value like "HasBled".
    - Verify it works : calling Peferences.Get("favorites", string.Empty); returns "HasBled" as expected
    - Close app and open it without building again (direct from phone)
    - I see no favorite and Preferences.Get("favorites", string.Empty) is string.Empty
    - I set it again, verify again, close app again and start again : still no value is registered...

    And because I had an error in my code, AND I updated Xamarin.Essentials in the same time I fixed the error, I don't where is the problem... Maybe I'll try with a new project...
  • LandLuLandLu Member, Xamarin Team Xamurai

    You could try it on a completely new project.
    It works fine on my side with Essential. Here is my environment:

    If the issue still persists on your side try to post your sample here.

  • galactosegalactose Member ✭✭
    edited May 1 Accepted Answer

    Hi,

    Sorry for the time it took. I finally solved my error ! (so, no trouble with Xamarin.Essentials that I successfully tested with the same version in another project...)

    To issue was with:

    namespace CardioCALC.ViewModels
    {
        public sealed class FavoritesViewModel : ViewModelBase
        {
            /* ...... */
    
            private FavoritesViewModel()
            {
                this.Favorites.CollectionChanged += OnFavoritesSaveChanges; // Autosave
            }
    
            // Auto-save favorites list with event
            private void OnFavoritesSaveChanges(object sender, NotifyCollectionChangedEventArgs e)
            {
                this.SaveFavorites();
            }
    
            public void SaveFavorites()
            {
                if (this.Favorites.Count > 0)
                    Preferences.Set(favoritePreferenceKey, this.Serialize());
    
                else Preferences.Remove(favoritePreferenceKey);
            }
        }
    }
    

    Which has to be:

            private void OnFavoritesSaveChanges(object sender, NotifyCollectionChangedEventArgs e)
            {
                if (e.Action == NotifyCollectionChangedAction.Add || e.Action == NotifyCollectionChangedAction.Remove)
                    this.SaveFavorites();
            }
    

    Otherwise, the Clear() call in my LoadSavedFavorites() method was erasing the Xamarin.Essentials.Preferences key !! This Clear() call is needed as I call LoadSavedFavorites() when the locale changes, so that all Score objects with new localized labels have their IsFavorite property set correctly.

    Thanks for your time,
    Galactose

  • TimotheeTimothee Member
    edited September 16

    Questions like this should be taken down, or their title changed to "Question about Xamarin Essentiels Preferences" to indicate ones might find some tips in here, but really nothing is wrong with Xamarin Essentiels Preferences.

    At the very least, please ad an EDIT section to the top of your question, indicating nothing is wrong. Such a time waster otherwise.

Sign In or Register to comment.