Welcome to OGeek Q&A Community for programmer and developer-Open, Learning and Share
Welcome To Ask or Share your Answers For Others

Categories

0 votes
102 views
in Technique[技术] by (71.8m points)

c# - Adding settings class to a UWP app

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?

question from:https://stackoverflow.com/questions/35470460/adding-settings-class-to-a-uwp-app

与恶龙缠斗过久,自身亦成为恶龙;凝视深渊过久,深渊将回以凝视…
Welcome To Ask or Share your Answers For Others

1 Reply

0 votes
by (71.8m points)
  1. Create a new class inheriting from ObservableSettings.
  2. Call to the base class constructor indicating if you want to store the settings in LocalSettings or in RoamingSettings.
  3. Add all your properties calling the base class members Set and Get in the getter and in the setter. No need to pass the name of the property or use nameof() operator!
  4. Optionally you can set a default value decorating the property with DefaultSettingValue attribute.

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.


与恶龙缠斗过久,自身亦成为恶龙;凝视深渊过久,深渊将回以凝视…
OGeek|极客中国-欢迎来到极客的世界,一个免费开放的程序员编程交流平台!开放,进步,分享!让技术改变生活,让极客改变未来! Welcome to OGeek Q&A Community for programmer and developer-Open, Learning and Share
Click Here to Ask a Question

...