使用C#封装一个UWP Applicaion Data的结构化存储类

简介

.Net 中,Applicaion Data 相当于一个结构化存储器,在存储一些配置信息的时候,使用非常方便。在应用更新以后,配置不会丢失,在应用写在以后会自动删除,并且也使用了加密存储,没有安全问题。

这里是关于 App Settings 的一些特性

  • 用来保存配置数据,最深 32 层,不限数量,可以保存在本地且可以漫游。
  • AppSettings 支持除二进制外的所有 WinRT 数据格式,如果存储二进制数据得用文件。
  • 系统只验证数据格式和长度,不验证数据是否正确。

主要存储类型

存储分为本地存储和进行漫游,漫游的话可以在多设备之间同步。

存储分为直接存储、Composite 设置集合和 Container 容器。 其中这些存储类型可以相互嵌套。Container 容器类似于一个文件夹可以作为许多设置的抽象集合,而 Composite 集合类似于一个文件夹,可以将同类的设置放一起,而直接存储可以存储单条信息。

Container 中能够包含多个 Composite 和单条键值对,而 Composite 中可以包含多条键值对。之后将根据这些不同的存储方法对 ApplicationData 进行封装。

代码实现

代码通过模拟 jQuery 的连缀操作,可以在单行完成存储复杂类型数据的操作。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
using System;
using System.Collections.Generic;
using Windows.Storage;

class SettingLib {

//声明存储容器
private ApplicationDataContainer dataSettings;

//声明一些临时变量
private string tempSettingName;
private object tempSettingValue;
private string tempContainerName;
private string tempCompositeName;
private ApplicationDataContainer tempContainer;
private ApplicationDataCompositeValue tempComposite;
private ApplicationDataCompositeValue tempReadComposite;

//是否自动清除缓存的变量
private bool isAutoClearTemp;

//构造函数,默认为漫游设置和自动清除历史设置的缓存
public SettingLib(bool isRoaming = true, bool isAutoClearTemp = true) {
if (isRoaming) {
dataSettings = ApplicationData.Current.RoamingSettings;
} else {
dataSettings = ApplicationData.Current.LocalSettings;
}
this.isAutoClearTemp = isAutoClearTemp;
tempContainer = null;
tempComposite = null;
tempReadComposite = null;
}

//创建直接存储,需要传入一个键值对
public SettingLib CreateSetting(string key, object value) {
tempSettingName = key;
tempSettingValue = value;
return this;
}
//创建存储集合,需要传入集合的名称和键值对的List
public SettingLib CreateComposite(string compositeName, List<Tuple<string, object>> vals) {
ApplicationDataCompositeValue composite = new ApplicationDataCompositeValue();
foreach (Tuple<string, object> v in vals) {
composite[v.Item1] = v.Item2;
}
tempComposite = composite;
tempCompositeName = compositeName;
return this;
}
//创建存储容器,需要传入容器的名称
//不考虑嵌套Container
public SettingLib CreateContainer(string containerName) {
ApplicationDataContainer container = dataSettings.CreateContainer(containerName, ApplicationDataCreateDisposition.Always);
tempContainer = container;
tempContainerName = containerName;
return this;
}

//将之前创建的各种存储类型进行组合之后进行存储
//可以在Container中包含Composite或者键值对,可以在Composite中包含多条键值对,可以直接存储键值对
//不考虑嵌套Container
public SettingLib SaveSetting() {
if (tempContainer != null) {
if (dataSettings.Containers.ContainsKey(tempContainerName)) {
if (tempComposite != null) {
dataSettings.Containers[tempContainerName].Values[tempCompositeName] = tempComposite;
} else {
dataSettings.Containers[tempContainerName].Values[tempSettingName] = tempSettingValue;
}
} else {
throw new ArgumentException();
}
} else {
if (tempComposite != null) {
dataSettings.Values[tempCompositeName] = tempComposite;
} else {
dataSettings.Values[tempSettingName] = tempSettingValue;
}
}
if (isAutoClearTemp) {
ClearTemp();
}
return this;
}

//一次操作后清除缓存的方法
public SettingLib ClearTemp() {
tempSettingValue = null;
tempContainer = null;
tempComposite = null;
tempReadComposite = null;
return this;
}
//如果没有设置自动清除缓存的话可以手动清除缓存,需要传入清除缓存的类型
public SettingLib ClearTemp(string content) {
switch (content) {
case "Setting":
tempSettingValue = null;
break;
case "Container":
tempContainer = null;
break;
case "Composite":
tempComposite = null;
break;
case "ReadComposite":
tempReadComposite = null;
break;
default:
throw new ArgumentException();
}
return this;
}

//读取键值对存储
public object ReadSetting(string key) {
object value = dataSettings.Values[key];
return value;
}

//读取Composite中的所有键值对,并且以List返回
//不考虑嵌套Container
public List<Tuple<string, object>> ReadSetting(string compositeName, List<string> settingNames) {
ApplicationDataCompositeValue composite;
if (tempReadComposite != null) {
composite = tempReadComposite;
} else {
composite = (ApplicationDataCompositeValue)ReadSetting(compositeName);
}
if (composite == null) {
return null;
} else {
List<Tuple<string, object>> cs = new List<Tuple<string, object>>();
foreach (string sn in settingNames) {
cs.Add(new Tuple<string, object>(sn, composite[sn]));
}
return cs;
}
}
//读取Container中指定名称的设置
//不考虑嵌套Container
public object ReadSetting(string containerName, string settingName) {
bool hasContiner = dataSettings.Containers.ContainsKey(containerName);
bool hasSetting = false;
object settingValue = null;
if (hasContiner) {
hasSetting = dataSettings.Containers[containerName].Values.ContainsKey(settingName);
}
if (hasSetting) {
settingValue = dataSettings.Containers[containerName].Values[settingName];
}
return settingValue;
}
//读取Container中设置集合中的所有键值对
public List<Tuple<string, object>> ReadSetting(string containerName, string compositeName, List<string> settingNames) {
tempReadComposite = (ApplicationDataCompositeValue)ReadSetting(containerName, compositeName);
List<Tuple<string, object>> ret = ReadSetting(null, settingNames);
if (isAutoClearTemp) {
ClearTemp();
}
return ret;
}

//删除某种设置
//不考虑嵌套Container
public void RemoveSetting(string settingName, bool isContainer = false) {
if (isContainer) {
dataSettings.DeleteContainer(settingName);
} else {
dataSettings.Values.Remove(settingName);
}
}

}

使用方法

可以使用连缀操作在单行进行复杂的设置

1
2
3
4
5
public void makeSettings() {
SettingLib settingLib = new SettingLib();
settingLib.CreateContainer("CampusNetwork").CreateSetting("campusNetworkAccountId", id).SaveSetting();
string id = (string)settingLib.ReadSetting("CampusNetwork", "campusNetworkAccountId");
}

需要注意的点:

  • 在存储的时候使用连续的 Create 创建结构化的存储,最后使用 SaveStting 方法进行最终存储。
  • 使用 ReadSetting 读取数据,具体使用可以参考 ReadingSetting 方法的每一种重载中的注释
  • 在创建结构化存储的时候,可以在 Container 中包含 Composite 或者键值对,可以在 Composite 中包含多条键值对,可以直接存储键值对

获取文中代码

在 GitHub 的 HelloBUPT 项目中可以得到代码:https://github.com/imaginezz/helloBUPT/blob/master/beiyou/CommonLibrary/SettingLib.cs

参考链接

Windows 10 UWP 开发:如何读取和保存设置:http://edi.wang/post/2015/11/20/uwp-read-write-settings?utm_source=tuicool&utm_medium=referral

windows 8 开发 Application Data:http://www.cnblogs.com/icuit/archive/2012/06/06/2538246.html

MSDN ApplicationDataContainer Class:https://msdn.microsoft.com/zh-cn/library/windows/apps/windows.storage.applicationdatacontainer.aspx