In the UWP Application model, reading and saving settings are very similar to WinRT API. The class we are using is ApplicationData.Current.LocalSettings
It is using key-value-pair to store settings.
LocalSettings
will stay on the user's current computer, and not being synced with thier Microsoft account.
The API to save settings is:
LocalSettings.Values[key] = value;
To read settings:
if (LocalSettings.Values.ContainsKey(key)) { return LocalSettings.Values[key]; }
Please notice, we should first check if the key is already present.
In order to use it in an easy way, we can write a class to manage those settings:
public class AppSettings : INotifyPropertyChanged { public bool ShowTimeSheetSetting { get { return ReadSettings(nameof(ShowTimeSheetSetting), true); } set { SaveSettings(nameof(ShowTimeSheetSetting), value); NotifyPropertyChanged(); } } public ApplicationDataContainer LocalSettings { get; set; } public AppSettings() { LocalSettings = ApplicationData.Current.LocalSettings; } private void SaveSettings(string key, object value) { LocalSettings.Values[key] = value; } private T ReadSettings<T>(string key, T defaultValue) { if (LocalSettings.Values.ContainsKey(key)) { return (T)LocalSettings.Values[key]; } if (null != defaultValue) { return defaultValue; } return default(T); } public event PropertyChangedEventHandler PropertyChanged; protected void NotifyPropertyChanged([CallerMemberName]string propName = "") { PropertyChanged?.Invoke(this, new PropertyChangedEventArgs(propName)); } }
Key Points:
1. By taking advantage of C#6, the key is a type of string
, we can use nameof
to retrieve it's name. When we invoke event handlers, we can also use ?.
for null check.
2. Using generics to do the type convertion. If the property got a default value, return it. Because in our App, default values are ususally needed. In this example, I only added one settings of a bool
type: ShowTimeSheetSetting
3. The operation that the AppSettings class is exposing is just the getter and setter on the property. Reading and Saving settings are automatically done internally. The user of this class don't have to know about how this is done, which means, if some day, the implementation for how to read and save settings changes, we just need to modify one place not everywhere in the code.
4. Because we implemented INotifyPropertyChanged
we can do two way bindings on XAML:
<Page.Resources> <core:AppSettings x:Key="AppSettings" /> </Page.Resources>
<ToggleSwitch OnContent="On" OffContent="Off" IsOn="{Binding Source={StaticResource AppSettings}, Path=ShowTimeSheetSetting, Mode=TwoWay}" />
For other types of settings, such as string
, int
, enum
, we can of course added them as properties, and use them in xaml just like this!
Gee
应该把 AppSetting 做成 singleton 的,否则当你有多个 AppSetting 的时候,通过一个修改不会导致另一个被修改。一个 workaround 是 public sealed class AppSetting : INotifyPropertyChanged { static PropertyChangedEventHandler propertyChanged; public event PropertyChangedEventHandler PropertyChanged { add { propertyChanged += value; } remove { propertyChanged -= value; } } } 以及 static T ReadSetting(string name, T def = default(T)) { object result; LocalSettings.Values.TryGetValue(name, out result); return result is T ? (T)result : d
_勤_
INotifyPropertyChanged 会因为多个 AppSettings实例而失灵的吧
lindexi
我不喜欢他自带的设置,我现在都是使用文件读取,因为这样可以用之前写的框架,做到兼容。如果软件升级了,可能让存放的数据无法兼容,所以就需要使用文件的方式,这样就不需要做改动,不知道要不要去写一个框架可以使用微软的设置来读取数据,在软件修改可以兼容
Jol E. Roger
//Global Variable public AppSettings AppSettings; // assigned in Mainpage constructor AppSettings = (AppSettings)Resources.First(res => res.Key.Equals("AppSettings")).Value;
Jol E. Roger
less code: AppSettings = Resources["AppSettings"] as AppSettings;