有些时候我们需要保存应用程序的设置,如用户的系统设定。在Android中,我们可以使用sharepreference。在Metro中我们该怎么做呢?



保存/读取基本类型数据


ApplicationData.Current.LocalSettings字典中,并保存在本地。程序在开始运行的时候会从本地初始化该字典。加载之前保存的数据。这样我们就可以方便的保存/读取基本类型数据了。


我将其封装成了一个工具类。


[csharp]  view plain copy print ?


1. using System;  
2. using System.Collections.Generic;  
3. using System.Linq;  
4. using System.Text;  
5. using System.Threading.Tasks;  
6. using Windows.Storage;  
7.   
8. namespace Win8_Study.Pages  
9. {  
10. class LocalDataUtil  
11.     {  
12.         #region 保存/读取基本类型数据  
13. public static void SaveData(string key, object value)  
14.         {  
15.             ApplicationData.Current.LocalSettings.Values[key] = value;  
16.         }  
17.   
18. public static object GetData(string key)  
19.         {  
20. return ApplicationData.Current.LocalSettings.Values[key];  
21.         }  
22.   
23.   
24. public static void RemoveData(string key)  
25.         {  
26.             ApplicationData.Current.LocalSettings.Values.Remove(key);  
27.         }  
28.         #endregion  
29.     }  
30. }


下面我们来看一个示例:




如何保存 RES文件 resolume怎么保存设置_序列化



默认显示的字体大小为24,我们将其字体改为28后返回到主页面,然后重新进入该页面。你会发现字体的大小变为28了。


重新启动程序进入该页面,你会发现字体的大小仍然为28。


下拉列表的选中项与字体大小是时刻对应的.



如何保存 RES文件 resolume怎么保存设置_System_02



实现方法如下


1.每次进入该页面的时候,首先获取之前保存的字体大小


a.没有获取到


将字体大小设为默认值


b.获取到


将字体大小设为获取的值


2.用户改变字体大小时,保存改变后的值

[csharp]  view plain copy print ?

1.     public sealed partial class LocalDataPage : Win8_Study.Common.LayoutAwarePage  
2.     {  
3. private readonly string TEXT_VALUE = "国米_百度百科\n" +  
4. "国际米兰足球俱乐部(Football Club Internazionale Milano,简称 Inter 或 Internazionale)" +  
5. "是一家位于意大利北部伦巴第区米兰市的足球俱乐部。";  
6. private readonly double TEXT_FONT_SIZE = 24;  
7. private readonly string TEXT_FONT_SIZE_KEY = "LocalDataPage-TEXT_FONT_SIZE_KEY";  
8.   
9. public LocalDataPage()  
10.         {  
11. this.InitializeComponent();  
12.         }  
13.   
14. protected override void LoadState(Object navigationParameter, Dictionary<String, Object> pageState)  
15.         {  
16.             Init();  
17.         }  
18.   
19.   
20. private void Init()  
21.         {  
22. //首先读取之前保存的设置,如果为空设置成默认状态  
23.             InitFontSize();  
24.             leftTextBlock.Text = TEXT_VALUE;  
25.         }  
26.   
27. protected override void SaveState(Dictionary<String, Object> pageState)  
28.         {  
29.         }  
30.   
31.         #region 保存程序设置  
32. private void OnLeftComboBoxSelectionChanged(object sender, SelectionChangedEventArgs e)  
33.         {  
34. as ComboBox;  
35. as ComboBoxItem;  
36.             SetTextFontSize(Convert.ToDouble(item.Content));  
37.         }  
38.   
39. private void SetTextFontSize(double size)  
40.         {  
41.             leftTextBlock.FontSize = size;  
42.             LocalDataUtil.SaveData(TEXT_FONT_SIZE_KEY, size);  
43.         }  
44.   
45. private void InitFontSize()  
46.         {  
47.             var obj = LocalDataUtil.GetData(TEXT_FONT_SIZE_KEY);  
48. double size = TEXT_FONT_SIZE;  
49. if (obj != null)  
50.             {  
51.                 size = Convert.ToDouble(obj);  
52.             }      
53. foreach (var element in leftFontSizeComboBox.Items)  
54.             {  
55. as ComboBoxItem;  
56. if (item.Content.ToString().Equals(size.ToString()))  
57.                 {  
58.                     leftFontSizeComboBox.SelectedItem = item;  
59. break;  
60.                 }  
61.             }              
62.         }  
63.         #endregion  
64.         ...  
65.     }

那么我们该怎样去保存非基本类型的数据呢?比如一个包含学生信息的集合?


保存/读取非基本类型的数据--序列化/反序列化


保存程序的实时数据是十分必要的。比如你从网络上获取了一些娱乐新闻并显示给用户,你需要将这些数据保存下来,以便程序下次运行的时候使用。


下次运行程序的时候,这些数据就会变成本地的了,加载速度会非常快,因为你不需要再去从网络获取数据。


如果你不这样做的话,用户可能会在网络非常拥塞的情况下看到一个非常"干净"的屏幕。这个时候你的应用也许会被(应该是必须)。。。



举一个"稍微"复杂点的例子


现在有Student,Coder两个类,它们都继承了父类People。


[csharp]  view plain copy print ?

1. using System;  
2. using System.Collections.Generic;  
3. using System.Linq;  
4. using System.Runtime.Serialization;  
5. using System.Text;  
6. using System.Threading.Tasks;  
7.   
8. namespace Win8_Study.Pages  
9. {  
10.     [DataContract]  
11. public abstract class People  
12.     {  
13.         [DataMember]  
14. public string Name { get; set; }  
15.         [DataMember]  
16. public int Age { get; set; }  
17.   
18. public People(string name,int age)  
19.         {  
20. this.Name = name;  
21. this.Age = age;  
22.         }  
23.     }  
24.   
25.     [DataContract]  
26. public class Student : People  
27.     {  
28.         [DataMember]  
29. public int Score { get; set; }  
30.   
31. public Student(string name, int age, int score)  
32. base(name, age)  
33.         {  
34. this.Score = score;  
35.         }  
36.     }  
37.   
38.     [DataContract]  
39. public class Coder : People  
40.     {  
41.         [DataMember]  
42. public int WorkYears { get; set; }  
43.   
44. public Coder(string name, int age, int workYears)  
45. base(name, age)  
46.         {  
47. this.WorkYears = workYears;  
48.         }  
49.     }  
50. }

我们需要在ListView上 随机显示一些学生和程序员的信息,并保存下来。然后清空ListView,读取保存的数据,看结果与之前的是否相同。



创建学生和程序员信息的方法很简单,在这里创建5-10条信息,每条信息的内容随机显示:


[csharp]  view plain copy print ?


1. private List<People> GetPeopleDatas()  
2.         {  
3. new List<People>();  
4. new Random(DateTime.Now.Millisecond);  
5. int count = ran.Next(5) + 5;//5 - 10  
6. for (int i = 0; i < count; ++i)  
7.             {  
8. int type = ran.Next(2);  
9. if (type == 0)  
10.                 {  
11. new Student("学生" + (i + 1), ran.Next(12) + 6, 60 + ran.Next(41)));  
12.                 }  
13. else  
14.                 {  
15. new Coder("程序员" + (i + 1), ran.Next(10) + 22, ran.Next(5)));  
16.                 }  
17.             }  
18. return peoples;  
19.         }


[csharp]  view plain copy print ?

1. private void OnRightRandomAddDataButtonClicked(object sender, RoutedEventArgs e)  
2.         {  
3.             _peoples = GetPeopleDatas();  
4.             SetListViewData(_peoples);  
5.         }


[csharp]  view plain copy print ?


1. private void SetListViewData(List<People> peoples)  
2. {  
3.     itemListView.Items.Clear();  
4. foreach (People p in peoples)  
5.     {  
6. new ListViewItem();  
7.         item.FontSize = 20;  
8. if (p is Student)  
9.         {  
10. as Student;  
11. string.Format("{0} 年龄:{1} 成绩: {2}", s.Name, s.Age, s.Score);  
12.         }  
13. else  
14.         {  
15. as Coder;  
16. string.Format("{0} 年龄:{1} 工作时间: {2}年", c.Name, c.Age, c.WorkYears);  
17.         }  
18.         itemListView.Items.Add(item);  
19.     }  
20. }  
  

[csharp]  view plain copy print ?

1.         private async void OnRightSaveDataButtonClicked(object sender, RoutedEventArgs e)  
2.         {  
3. typeof(List<People>));  
4. string.Format("保存数据成功! item数量{0}",_peoples.Count), "提示");  
5.         }

其中 SerializerUtil.XMLSerialize是我封装的序列化代码的方法,其实现方式如下:


[csharp]  view plain copy print ?

1. public static async Task XMLSerialize(object instance, Type type)  
2. {  
3. //取得当前程序存放数据的目录  
4.     StorageFolder folder = Windows.Storage.ApplicationData.Current.LocalFolder;  
5. //定义文件名  
6. string fileName = "LocalDataPage-list_data.xml";  
7. //创建文件,如果文件存在就覆盖  
8.     StorageFile newFile = await folder.CreateFileAsync(fileName, CreationCollisionOption.ReplaceExisting)  
9. //将内容序列化至文件  
10.     Stream newFileStream = await newFile.OpenStreamForWriteAsync();  
11. new DataContractSerializer(type, GetTypes());  
12.     ser.WriteObject(newFileStream, instance);  
13.     newFileStream.Dispose();  
14. }


[csharp]  view plain copy print ?


    1. private static ObservableCollection<Type> GetTypes()  
    2.         {  
    3. //添加要序列化的类型  
    4. if (_Types == null)  
    5.             {  
    6. new ObservableCollection<Type>();  
    7. typeof(People));  
    8. typeof(Student));  
    9. typeof(Coder));  
    10.             }  
    11. return _Types;  
    12.         }


    至此,数据就保存好了。



    读取数据


    读取数据也就是进行反序列化,我们可以得到之前保存的对象集合,其数据类型是List<People>,然后我们将该对象集合交给ListView显示即可。


    [csharp]  view plain copy print ?

    1. private async void OnRightLoadDataButtonClicked(object sender, RoutedEventArgs e)  
    2.         {  
    3. try  
    4.             {  
    5. typeof(List<People>));  
    6. as List<People>;  
    7.                 SetListViewData(_peoples);  
    8. string.Format("读取数据成功! item数量{0}", _peoples.Count),  
    9. "提示");  
    10. return;  
    11.             }  
    12. catch (FileNotFoundException)  
    13.             {  
    14.                   
    15.             }  
    16. "你还没有保存数据。", "提示");  
    17.         }

    反序列化


    [csharp]  view plain copy print ?

    1. public static async Task<object> XMLDeserialize(Type type)  
    2.        {  
    3.            StorageFolder folder = Windows.Storage.ApplicationData.Current.LocalFolder;  
    4. string fileName = "LocalDataPage-list_data.xml";  
    5.            StorageFile newFile = await folder.GetFileAsync(fileName);  
    6.            Stream newFileStream = await newFile.OpenStreamForReadAsync();  
    7. //进行反序列化  
    8. new DataContractSerializer(type, GetTypes());  
    9. object instance = ser.ReadObject(newFileStream);  
    10.            newFileStream.Dispose();  
    11. return instance;  
    12.        }



    程序运行的效果如下:


    1.随机显示学生和程序员信息:



    如何保存 RES文件 resolume怎么保存设置_序列化_03


    2.保存数据



    保存文件的内容


    [html]  view plain copy print ?


      1. <ArrayOfPeople xmlns="http://schemas.datacontract.org/2004/07/Win8_Study.Pages" xmlns:i="http://www.w3.org/2001/XMLSchema-instance"><People i:type="Student"><Age>14</Age><Name>学生1</Name><Score>66</Score></People><People i:type="Coder"><Age>24</Age><Name>程序员2</Name><WorkYears>4</WorkYears></People><People i:type="Student"><Age>7</Age><Name>学生3</Name><Score>86</Score></People><People i:type="Coder"><Age>23</Age><Name>程序员4</Name><WorkYears>1</WorkYears></People><People i:type="Coder"><Age>25</Age><Name>程序员5</Name><WorkYears>2</WorkYears></People></ArrayOfPeople>


      3.清除数据并读取之前保存的数据


      显示效果同第一张图.