Skip to content
Introducing AI Conversations: Natural Language Interaction for Your Apps! Learn More

Persistent Properties

The most powerful feature of Stores. Mark a partial property with [Bind] and the DI source generator emits a getter/setter that reads from and writes to the backing key/value store — no INotifyPropertyChanged, no runtime reflection, no manual wiring. The class is automatically rehydrated on every read, so it survives app restarts.

  1. Create a partial class with partial properties marked [Bind]:

    using Shiny;
    public partial class AppSettings
    {
    [Bind] // default store
    public partial string Theme { get; set; }
    [Bind]
    public partial bool NotificationsEnabled { get; set; }
    [Bind("secure")] // secure store
    public partial string Token { get; set; }
    [Bind(Key = "ui_density")] // override the storage key (defaults to property name)
    public partial int Density { get; set; }
    }
  2. Register it like any other service (the generator handles construction):

    [Singleton]
    public partial class AppSettings { /* same as above */ }

    Or hand-write the registration if you prefer:

    builder.Services.AddSingleton<AppSettings>();
  3. Inject and use — every set persists, every get reads from the store:

    public class SettingsViewModel(AppSettings settings)
    {
    public void ToggleNotifications()
    {
    settings.NotificationsEnabled = !settings.NotificationsEnabled;
    }
    }

If you don’t need binding, access the stores directly via the Shiny.Stores static accessor:

Shiny.Stores.Default.Set("theme", "dark");
var theme = Shiny.Stores.Default.Get<string>("theme");
Shiny.Stores.Secure.Set("token", "abc123");
// Arbitrary keyed stores
Shiny.Stores.Keyed("my-store").Set("k", "v");

The static accessor is self-bootstrapping on mobile/desktop — Default and Secure lazily construct the platform-native store on first access, so generated [Bind] property getters work as soon as the type is constructed. On Blazor WebAssembly (where the store needs IJSRuntime from the built provider) call host.Services.UseShinyStores() after host.Build() to snapshot the DI-resolved store into the static accessor.

For tests, use Shiny.Stores.Register(key, store) to swap in a MemoryKeyValueStore or any custom double, and Shiny.Stores.Reset() to clear state between runs.