pbX Settings Plugin for UWP, iOS, macOS, tvOS, watchOS, Android and .NET

Hello and greetings to all :)

I would like to introduce my first plugin for Xamarin (and .NET).

Source code: https://github.com/boguslawski-piotr/pbX/tree/master/Plugin.pbXSettings

NuGet package: https://www.nuget.org/packages/Xam.Plugins.pbXSettings

pbX Settings Plugin for UWP, iOS, macOS, tvOS, watchOS, Android and .NET

Plugin (actually simple class Plugin.pbXSettings.Settings and Plugin.pbXSettings.SettingsStorage pair) that makes it easy to handle all sorts of settings, more precisely, values of any type that is accessed through a key.

This plugin was inspired by another similar component written by James Montemagno, but I used a different approach for data handling, interface and usage.

This plugin uses the native settings storage, which means all settings are persisted across app updates, saved natively, and on some platforms synchronized between devices.

  • Android: SharedPreferences
  • Apple: NSUserDefaults
  • UWP: ApplicationDataContainer
  • .NET / .NET Core 2: UserStore -> IsolatedStorageFile

The main plugin class Plugin.pbXSettings.Settings is fully ready for use in any binding systems because implements interface INotifyPropertyChanged. Can also be used as a regular collection, that is, it can be enumerated :)

This plugin uses .NET DataContractSerializer for saving and restoring keys and values, which means you can put and retrieve practically any valid .NET object as long as it meets the requirements of this serialization technolgy: https://docs.microsoft.com/en-us/dotnet/api/system.runtime.serialization.datacontractserializer?view=netframework-4.5.1

Installation

Just install NuGet package Xam.Plugins.pbXSettings NuGet into your PCL project (if you have any)) and all application projects (for each platform there is at least one project).

Platform Support

  • Universal Windows Platform
  • Xamarin.iOS
  • Xamarin.Mac
  • Xamarin.watchOS
  • Xamarin.tvOS
  • Xamarin.Android (compiled for API 19)
  • .NET 4.5 (and later versions)
  • .NET Core 2 / .NET STandard 2 (soon)

Also

  • Plugin works OK with Xamarin.Forms (PCL or Shared)

Getting started

Basic use

using Plugin.pbXSettings;

// on first run it should return: 0
// on next runs it should return: 1
int i = Settings.Current.Get<int>("test");
Settings.Current.Set(1, "test");

// it should return: 13
i = Settings.Current.Get<int>("second test", 13);

// on first run it should return: "" (empty string)
// on next runs it should return: smile, the wold will be better 
string s = Settings.Current.Get<string>("my string");
Settings.Current.Set("smile, the wold will be better", "my string");

// And so on, with all the basic types of data.

You can use your class that inherits after Plugin.pbXSettings.Settings

class MySettings : Settings
{
    [Default(17)]
    public int IntValue
    {
        // You don't need to provide key name :), compiler will do it for you.
        get => Get<int>();
        set => Set(value);
    }

    // [Default(new DateTime(2010, 10, 10))] 
    // can't use attribute for non constants :(
    public DateTime DateTimeValue
    {
        get => Get<DateTime>();
        set => Set(value);
    }

    // but you can use GetDefault method :)
    protected override object GetDefault(string key)
    {
        if (key == "DateTimeValue")
            return new DateTime(2010, 10, 10);
        return base.GetDefault(key);
    }

    // or provide default value other way
    public DateTime DateTimeValue2
    {
        get => Get<DateTime>(nameof(DateTimeValue2), new DateTime(2005, 10, 10));
        set => Set(value);
    }
}

MySettings mySet = new MySettings();

// on first run it should return: 17
// on next runs it should return: 34
i = mySet.IntValue;
mySet.IntValue = 34;

// on first run it should return: 10/10/2010
// on next runs it should return: 10/10/2000
DateTime dt = mySet.DateTimeValue;
mySet.DateTimeValue = new DateTime(2000, 10, 10);

// should return: 10/10/2005
dt = mySet.DateTimeValue2;

// defines value that is not a property
mySet.Set(true, "BoolValue");

You can use as many as you want set of settings

// this uses default settings
int i = Settings.Current.Get<int>("test");
Settings.Current.Set(1, "test");

// this uses 'my set 2' set, completely separate from others
Settings otherSet = new Settings("my set 2");
i = otherSet.Get<int>("test");
otherSet.Set(2, "test");

You can use set of settings as collection

foreach (var kv in mySet)
{
    Console.WriteLine($"{kv.Key} = {kv.Value.ToString()}");
}

You can delete keys/values or clear entire collection

bool exists = mySet.Contains("IntValue"); // true
exists = mySet.Contains("IntValue2");     // false

// removes value from storage
mySet.Remove("BoolValue");

// clears entire set of settings
mySet.Clear();

You can use low level access to platform settings storage

public interface ISettingsStorage
{
    Task<string> GetStringAsync(string id);
    Task SetStringAsync(string id, string d);
}

// and use

SettingsStorage.Current

// object which is type SettingsStorage that implements ISettingsStorage

More documentation

Here: https://boguslawski-piotr.github.io/pbX/api/pbXNet.Settings.html you will find full documentation for pbXNet.Settings class which is a base class for Plugin.pbXSettings.Settings.

Contributions

Contributions are welcome. If you find a bug please report it and if you want a feature please describe it clearly and place it in Issues with 'enhancement' label.

If you want to contribute code please file an issue and create a branch off of the current dev branch and file a pull request.

License

Under MIT, see LICENSE file.

Posts

  • N_BauaN_Baua INMember ✭✭✭✭✭

    Hi @PiotrBoguslawski ,

    This is awesome man, I can see this plug-in is going to rock. Great
    And I am sure this won't be your last plug-in. :star: :star: :star: :star: :star:

    One question, though I know this plug-in can be extended easily, just curious to ask if it supports Byte[] and Base64 String datatypes as well. If Yes, Could you update your document examples for the same, please.

    Kudos for your your efforts, thanks.

    Regards,
    N Baua

  • Thank you for the kind words :)

    Yes, arrays work.

    byte[] a = Settings.Current.Get<byte[]>("array");
    if (a == null)
    {
        // on first run returns null (no key array in settings)
        a = new byte[] { 101, 102, 103, 104, 105, 1, 2, 3, 4, 5 };
        Settings.Current.Set(a, "array");
    }
    
    // on second run it returns
    -   a   {byte[10]}  byte[]
        [0] 101 byte
        [1] 102 byte
        [2] 103 byte
        [3] 104 byte
        [4] 105 byte
        [5] 1   byte
        [6] 2   byte
        [7] 3   byte
        [8] 4   byte
        [9] 5   byte
    
    

    Base64 string is a normal string imo, there is nothing special about it and it will work as any other string.
    You can use :

    string sa = Convert.ToBase64String(a);
    Settings.Current.Set(sa, "base64array");
    ...
    ...
    // in another place and some time later...
    string sa = Settings.Current.Get<string>("base64array");
    byte[] a = Convert.FromBase64String(sa);
    
  • N_BauaN_Baua INMember ✭✭✭✭✭

    Hi @PiotrBoguslawski,

    Thanks for the quick response, on the note of Base64 string, ...
    I had issues with the other settings plug-in retrieving the same value back (names of author solicited - hes going great, bit occupied though). Haven't raised an issue back yet, I am trying to resolve it on own unless I have to modify the owner's code.

    on your plug-in, I assume the core code still uses the string (String base class) even for larger strings like Base64, can that be StringBuilder for the performance(memory management point of view - immutability etc), just a wild thought . Please share your idea.

    Thanks again for your time.

    Regards,
    N Baua

  • Hi

    I'm not really sure what you mean. In general, settings should not be used to store large amounts of data or important user data. For this type of data would rather use a file system or database.

    In my pbX library, which I am slowly creating, you can find several different classes for this type of task. For example:

    IFileSystem
        DeviceFileSystem
        EncryptedFileSystem
        FileSystemInDatabase
    IStorage<T>
        StorageOnAzureStorage<T>
        StorageOnFileSystem<T>
    
  • N_BauaN_Baua INMember ✭✭✭✭✭

    Oooh voila,

    I guess I am falling in love with this plug-in.
    I'll dig deep this on coming Sunday, can't get enough time to breath, just reached home.

    Wow, this is awesome. (Yeah I am using JSON file for large data, but its kinda slow, now I got a competitor :wink: to test.)

    Thanks for your reply.

    N Baua

Sign In or Register to comment.