I'm developing a Universal Windows Platform app but there is no Settings template in Visual Studio.
How can I implement an easy, strongly typed and observable class that stores my settings in LocalSettings or RoamingSettings?
Settings stored here are kept on the device. Windows. Storage. ApplicationData.
Microsoft continues to baby-step around the obvious, but it has officially deprecated the Universal Windows Platform (UWP) as it pushes the desktop-focused Windows App SDK (formerly called Project Reunion) and WinUI 3 as the future of Windows application development.
Here an example of a settings class:
namespace Test { public class Settings : ObservableSettings { private static Settings settings = new Settings(); public static Settings Default { get { return settings; } } public Settings() : base(ApplicationData.Current.LocalSettings) { } [DefaultSettingValue(Value = 115200)] public int Bauds { get { return Get<int>(); } set { Set(value); } } [DefaultSettingValue(Value = "Jose")] public string Name { get { return Get<string>(); } set { Set(value); } } } }
and here how to add an instance in your app.xaml:
<Application x:Class="Test.App" xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation" xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml" xmlns:local="using:Test" RequestedTheme="Light"> <Application.Resources> <local:Settings x:Key="settings"/> </Application.Resources> </Application>
Access and modify the values in a MVVM fashion:
<Page x:Class="Test.MainPage" xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation" xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml" xmlns:local="using:Test" xmlns:d="http://schemas.microsoft.com/expression/blend/2008" xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006" mc:Ignorable="d" DataContext="{StaticResource settings}"> <StackPanel Background="{ThemeResource ApplicationPageBackgroundThemeBrush}"> <TextBlock Text="Bauds"/> <TextBox Text="{Binding Default.Bauds, Mode=TwoWay}"/> <TextBlock Text="Name"/> <TextBox Text="{Binding Default.Name, Mode=TwoWay}"/> </StackPanel> </Page>
Everything will be stored properly in your settings repository.
Here you have the implementation of DefaultSettingValue and ObservableSettings:
using System.Collections.Generic; using System.Linq; using System.Runtime.CompilerServices; using System.Reflection; using System.ComponentModel; using Windows.Storage; [AttributeUsage(AttributeTargets.Property, AllowMultiple = false)] public sealed class DefaultSettingValueAttribute : Attribute { public DefaultSettingValueAttribute() { } public DefaultSettingValueAttribute(object value) { Value = value; } public object Value { get; set; } } public class ObservableSettings : INotifyPropertyChanged { private readonly ApplicationDataContainer settings; public ObservableSettings(ApplicationDataContainer settings) { this.settings = settings; } public event PropertyChangedEventHandler PropertyChanged; protected bool Set<T>(T value, [CallerMemberName] string propertyName = null) { if (settings.Values.ContainsKey(propertyName)) { var currentValue = (T)settings.Values[propertyName]; if (EqualityComparer<T>.Default.Equals(currentValue, value)) return false; } settings.Values[propertyName] = value; PropertyChanged?.Invoke(this, new PropertyChangedEventArgs(propertyName)); return true; } protected T Get<T>([CallerMemberName] string propertyName = null) { if (settings.Values.ContainsKey(propertyName)) return (T)settings.Values[propertyName]; var attributes = GetType().GetTypeInfo().GetDeclaredProperty(propertyName).CustomAttributes.Where(ca => ca.AttributeType == typeof(DefaultSettingValueAttribute)).ToList(); if (attributes.Count == 1) return (T)attributes[0].NamedArguments[0].TypedValue.Value; return default(T); }
You can download a solution with a functional example from the repository I created in GitHub.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With